CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Multiple instances of javascript webparts on the same page

Javascript has become popular among many SharePoint developers thanks to easy and fast jQuery, CSOM, SPServices and many other javascript libraries.  That can make solutions modern and fast. On the other hand developers should be aware of more things (some of them at Bamboo Team Blog). One of those is scoping of javascript webparts. The problem a developer has to consider: what happens if a user creates two or more instances of the same beautiful webpart on the page?

Let’s go and lab 🙂

I’ll create a solution for this lab: sp-lend-id.ikkelen. This time it will be a sandboxed solution.

This solution contains a webpart:

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Control Language="C#" AutoEventWireup="true" 
    CodeBehind="Ikkelen.ascx.cs" Inherits="sp_lend_id.ikkelen.Ikkelen.Ikkelen" %>
<link rel="stylesheet" href="/sp-lend-id/ikkelen.css"/>
<script type="text/javascript" 
    src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" 
    src="/sp-lend-id/ikkelen.js"></script>
<div id="notification-area"></div>
<input type="button" id="clickMe" value="Click me to show a notification"/>

a javascript file:

function notifyIkkelen() {
    jQuery("#notification-area")
        .append(jQuery("<div class='notification'>Tada!</div>"));
}
function initIkkelen() {
    jQuery("#clickMe").on({
        click: notifyIkkelen
    });
}
jQuery(document).on({
    ready: initIkkelen
});

And a css file for notifications inpired from twitter bootstrap alerts:

.notification {
    font-size: 20px;
    padding: 8px 35px 8px 14px;
    margin-bottom: 18px;
    color: #C09853;
    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
    background-color: #FCF8E3;
    border: 1px solid #FBEED5;
    border-radius: 4px;
}

Well let’s add to a page:

It works just fine. Now it’s time to add another one:

Well, this doesn’t work as it is excepted. When you click on the first button, it creates two notifications, when you click on the second button (which has the same id), nothing happens.

What shall we do about it?

Proposition 1: Make advantage of ASP.NET built-in id genereation

If you want to use your ids and make sure they don’t conflict, just add runat=”server” to your divs and in jQuery selector use ClientID:

That generates unique ids. But unfortunately it isn’t enough:

Now every time I click on the first button or the second button a notification is added to the second notification area (with the last loaded auto-generated id).

Allright, what if we “scope” it by using an anonymous function as a click event listener which won’t be overwritten:

function initIkkelen() {
    jQuery("#<%= clickMe.ClientID %>").on({
        click: function() {
            jQuery("#<%= notificationArea.ClientID %>")
                .append(jQuery("<div class='notification'>Tada!</div>"));
            }
    });
}
jQuery(document).on({
    ready: initIkkelen
});

And it works:

Okay, it works, but it sucks. You must use anonymous functions, you must put your javascript directly into markup, you must user runat=server which will generate other junk along your ids. It must be another way. We start over. Put the javascript code back to ikkelen.js, remove runat=server and ClientID.

Proposition 2. Use webpart scopes

First of all we have to remove all ids, because ids cannot be used more than once on a page. We can use just class attributes as in many projects. But there can be problems as well, because class attributes are a designer’s domain. Your solution should not break if you as designer then add and remove classes to adjust the look. Let’s take inspiration from jQuery Mobile and data-role attributes.
Ikkelen.ascx:

<div data-role="notification-area"></div>
<input type="button" data-role="clickMe" value="Click me to show a notification"/>

ikkelen.js:

function notifyIkkelen() {
    jQuery("[data-role='notification-area']")
        .append(jQuery("<div class='notification'>Tada!</div>"));
}

function initIkkelen() {
    jQuery("[data-role='clickMe']").on({
        click: notifyIkkelen
    });
}

$(document).on({
    ready: initIkkelen
});

Well, id problem is solved, but the events are fired four times:

Here when I click every button, four notification are added.

Now we must find out how we can limit our javascript and especially jQuery selectors to only one webpart. First of all we close our javascript code to a module:

(function($) {
    function notifyIkkelen() {
        $("[data-role='notification-area']")
            .append($("<div class='notification'>Tada!</div>"));
    }

    function initIkkelen() {
        $("[data-role='clickMe']").on({
            click: notifyIkkelen
        });
    }

    $(document).on({
        ready: initIkkelen
    });
})(jQuery);

The next question is what we can use to define a webpart scope. Let’s try to get current webpart id by using this.ClientID and put the id into our module, so it’s time to rewrite the module:

function ikkelen($, webpartId) {
    var webpart;
    function notifyIkkelen() {
        webpart.find("[data-role='notification-area']")
            .append($("<div class='notification'>Tada!</div>"));
    }

    function initIkkelen() {
        webpart = $("#" + webpartId);
        webpart.find("[data-role='clickMe']").on({
            click: notifyIkkelen
        });
    }

    $(document).on({
        ready: initIkkelen
    });
}

In this module which will be invoked in every instance of our webpart we create a jQuery reference to webpart (document ready). and traverse html elements only inside a webpart, by using jQuery find function.

So when we put the current webpart id into our ikkelen function along with jQuery reference:

<script type="text/javascript">
    ikkelen(jQuery, "<%= this.ClientID %>");
</script>

It works as expected:

Now a new notification is added in the webpart in which I click on the button.

Do you have other ideas about this topic? Let me know!

As I said, check out the code in my github repository:  sp-lend-id.ikkelen.

UPDATE.

If the webpart is  the classical visual webpart (farm solution, with a user control), use Parent instead of this:

(jQuery, "<%= this.Parent.ClientID %>")
Advertisements

3 responses to “Multiple instances of javascript webparts on the same page

  1. Björn 2012-09-06 at 13:47

    Module pattern rocks! And with this pattern, it’s easily integrated into SP. Awesome!

    • Anatoly Mironov 2012-09-06 at 14:15

      Thank you Björn! When developing javascript solutions for SharePoint it is not taken much attention to the fact that the webparts can be provisioned multiple times and in pages and contexts we don’t know about. So encapsulating the javascript code and using modules gives us more control und encreases the product quality.

  2. Arumoy 2015-06-04 at 07:53

    Thank you. Great article. It saves my day.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Вула Чăвашла

VulaCV - Чăвашла вулаттаракан сайт

Discovering SharePoint

And going crazy doing it

Bram de Jager talking Office 365, SharePoint and Azure

My view and thoughts on Productivity and more.

My programming life

and everything in between

SharePoint Development Lab by @avishnyakov

It is a good place to share some SharePoint stories and development practices.

SharePoint Dragons

Nikander & Margriet on SharePoint

RealActivity - Real-time and trustworthy

Blog site of founder, RealActivty - Paul J. Swider

Mai Omar Desouki - Avid SharePointer

Egyptian & Vodafoner - Senior SharePoint Consultant

Cameron Dwyer | Office 365, SharePoint, Outlook, OnePlace Solutions

Office 365, SharePoint, OnePlace Solutions & Life's Other Little Wonders

paul.tavares

Me and My doings!

Share SharePoint Points!!

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

SPJoel

SharePoint for everyone

SharePointRyan

Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode, ya mama

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint

%d bloggers like this: