In this article we’ll look at a very handy way of creating a custom solution to allow us to collect votes on practically any list within SharePoint online.

In this scenario we have a nomination system that allows staff to vote for other staff members to be awarded a prize for their hard work (we will not be running through setting that part up here). At the end of the month a report is generated showing alvl of the nominations for that particular month, an e-mail is then sent out with the details of each nomination to allow certain people to vote on who the winner should be.

So how does this work?
1) Responsible person starts the voting process by pressing a button in the overview Centre


2) A new screen appears asking for the Month and Year to be generated

3) A workflow runs in the background to pull out all of the nomination forms for that particular month and year
4) An e-mail is sent to the judges containing a link to each nomination form and a button to vote for each of the users (one vote per person per nomination)

When the receipt of the e-mail clicks on to one of the Vote for me! buttons they are taken to the following screen:

If everything goes well then the following screen will be presented to the user:

If there is a technical problem with the request (query to the list can’t be made for example) then the following screen will appear:

If the user has already voted once for the nomination form then the following message will appear:

How to set this up?

  1. In the List/Library you will using to record the votes make sure two fields exists with the following internal names

    Tip: create the fields with the same display name first to create the same internal name and then rename them afterwards to whatever you want, otherwise rename the fields within the script below to match

       
  2. Within the SharePoint site that hosts the list/library create a new page (name it whatever you want)
  3. Edit the page and copy the content below into the page either via JS injection or by using a Content/Script editor:Note: The spinning icon within this code needs font-awesome in order to work correctly, download the css package from here and then place it to be loaded within the page as per below code.

    ​<link rel=”stylesheet” href=”/SiteAssets/font-awesome.min.css”>

    <div>

    <div id=”msg” style=”text-align: center;”>Please wait…..

    <i id=”icon2″ style=”font-size:84px”></i>
    </div>

    </div>

  4. Add the following code to a JavaScript file and place this to be loaded within the page (you can use a content editor pointing to the new file to have SharePoint load the file for you)
    Note: Make sure you rename all instances of “Chief Executive Award Votes” to match the name of your own List/Library

    //The two following scripts have to be loaded on the page if they are not already:
    //sp.workflowservices.js
    //SP.Runtime.js

    SP.SOD.executeFunc(‘sp.js’, ‘SP.ClientContext’, init);

    function init() {
    $.getScript(SP.Utilities.Utility.getLayoutsPageUrl(‘sp.js’), function () {
    getDetails();
    });
    }
    //dialog element to show during processing
    var dlg = null;

    //Extract item ID from the URL parameter
    function getDetails() {
    if (!document.URL.split(“?”)[1]) {
    errorMsg();
    } else {

    var params = document.URL.split(“?”)[1].split(“&”);
    var ItemID;
    // Extracts the property values from the query string.
    for (var i = 0; i < params.length; i = i + 1) {
    var param = params[i].split(“=”);
    if (param[0] == “ItemID”)
    ItemID = decodeURIComponent(param[1]);
    }
    if (ItemID == null) {
    console.log(“No item ID provided”);
    errorMsg();
    } else {
    GetSiteUrl(ItemID);
    }
    }
    };

    //Get URL of the site
    function GetSiteUrl(itemId) {
    var ctx = new SP.ClientContext();
    var site = ctx.get_web();
    ctx.load(site, ‘Url’);
    ctx.executeQueryAsync(function (s, a) {
    getVote(itemId, site.get_url())
    });
    }

    //Get the details of the item including the total votes so far and the users who have voted for it
    function getVote(itemId, SiteURL) {
    var TotalVotes = “”;
    var VotedBy = “”;
    var clientContext = new SP.ClientContext(SiteURL);
    var oList = clientContext.get_web().get_lists().getByTitle(‘Chief Executive Award Votes’);

    var camlQuery = new SP.CamlQuery();
    var q = “<View><RowLimit>7</RowLimit><Query><Where><Eq><FieldRef Name=’ID’ /><Value Type=’Integer’>” + itemId + “</Value></Eq></Where></Query></View>”;
    camlQuery.set_viewXml(q),
    this.itemVote = oList.getItems(camlQuery),
    clientContext.load(this.itemVote),
    clientContext.executeQueryAsync(
    function (sender, args) {
    var itemCount = itemVote.get_count();
    if (itemCount > 0) {
    var listEnumerator = itemVote.getEnumerator();
    while (listEnumerator.moveNext()) {
    var item = listEnumerator.get_current();
    TotalVotes = item.get_item(‘Number_x0020_of_x0020_votes’);
    if (!TotalVotes) {
    TotalVotes = 0;
    }
    VotedBy = item.get_item(‘Voted_x0020_by’);
    }
    } else {
    TotalVotes = 0;
    }
    addVote(itemId, SiteURL, VotedBy, TotalVotes);
    },
    function (sender, args) {
    alert(‘Woops – something went wrong trying to check previous votes – please try again and if the problem continues please contact the IT Service Desk. The error is:’ + args.get_message() + ‘n’ + args.get_stackTrace());
    }
    );
    };

    //function to add a vote to the item for the current user
    function addVote(itemId, SiteURL, VotedBy, TotalVotes) {
    var userName = _spPageContextInfo.userDisplayName;
    var clientContext = new SP.ClientContext(SiteURL);
    var oList = clientContext.get_web().get_lists().getByTitle(‘Chief Executive Award Votes’);
    this.oListItem = oList.getItemById(itemId);
    TotalVotes = TotalVotes + 1;
    if (VotedBy==null) {
    VotedBy = “”;
    }
    //Check if user has already voted for the same item and throw a message if they have
    if (VotedBy.indexOf(userName) > -1) {
    $(‘#msg’)[0].innerHTML = “Woops.. it looks like you’ve already voted for this nomination

    It wouldn’t be fair to vote for the same one twice :)”;
    } else {
    if (!VotedBy) {
    VotedBy = userName;
    } else {
    VotedBy = VotedBy + “; ” + userName;
    }
    //Update the item in the list with the new vote and user details
    oListItem.set_item(‘Voted_x0020_by’, VotedBy);
    oListItem.set_item(‘Number_x0020_of_x0020_votes’, TotalVotes);
    oListItem.update();
    showInProgressDialog();
    clientContext.executeQueryAsync(
    function (sender, args) {
    if (dlg != null) {
    $(‘#msg’)[0].innerHTML = “Thank you for voting! 🙂

    You will now be redirected to the homepage”;
    dlg.close();
    setTimeout(function () {
    window.location.replace(SiteURL);
    }, 1000);
    }
    },
    function (sender, args) {
    closeInProgressDialog(SiteURL);
    alert(‘Woops – something went wrong trying to add the vote – please try again and if the problem continues please contact the IT Service Desk. The error is:’ + args.get_message() + ‘n’ + args.get_stackTrace());
    }
    )
    }
    }

    function showInProgressDialog() {
    if (dlg == null) {
    dlg = SP.UI.ModalDialog.showWaitScreenWithNoClose(“Please wait…”, “Submitting your vote…”, null, null);
    }
    }

    function closeInProgressDialog(SiteURL) {
    if (dlg != null) {
    document.getElementById(“msg”).innerHTML=”Thank You”;
    dlg.close();
    setTimeout(function(){window.location.replace(SiteURL);},1000);
    }
    }

    function errorMsg() {
    $(‘#msg’)[0].innerHTML = “Woops.. something went wrong 🙁

    Please try again or contact the IT Service Desk”;
    }

  5. Now we have a page ready to accept incoming votes! The next step is to setup the e-mail that gets sent out to the users with the link to voteThe vote link is quite simply the address of the page you just created followed by ?ID=itemIDFor example https://mytenancy.sharepoint.com/Votes/VoteNow.aspx?ID=2:In the next post we’ll look at creating the e-mail shown in this post so users can simply click a button to vote – coming soon