Unique Variables in Instances of Plugins

I’m writing a plugin that might be used several times in an app but which need to have unique parameters. I assumed that each instance would keep it’s variables separate from others but that doesn’t seem to be the case. So how can I keep everything in each instance of the plugin unique?

1 Like

Hi Jon.

Are you using actions tied to plugin elements or just plugin actions?

No actions at all (yet). I have a plugin that just has some JS that puts a border around an image. The image URL and border definition are passed to the plugin. But I need to have multiple instances so I can have multiple framed images. Each image and frame would be different.

I thought using the instance or instance.canvas parameter as a prefix would give me access to each plugin instance uniquely but that combination throws an error.

For example the plugin creates div for the image and border like this:

var newDiv = $('<div class="innermatte"><img id=imagetarget class="imagetarget"/></div>');

But how do I now modify imagetarget uniquely in each instance?

How are you doing that? And can you show an example, maybe a partial print screen, of how you’re injecting/using one instance in your bubble app?

I’m asking because different ways of using custom code offer different tools.

Thanks for the interest Vini! I can give you the whole thing. It’s pretty simple and there is a lot of junk in here (I’m removing css variables for defining css in JS so all the document.body.style.setProperty lines are being replaced):

Here’s the initialise function:

function(instance, context) {

  	modImgWidth = 510;
  	modImgHeight = 634;

  var newDiv = $('<div class="innermatte"><img id=imagetarget class="imagetarget"/></div>');
  console.log("instance: " + instance.class);
  console.log("instance.canvas: " + instance.canvas.class);
  //instance.canvas.css("background", "#ff00f0"); // for testing, makes it easier to find the bubble canvas

    imagetarget = $(".imagetarget").croppie({
 //    imagetarget = $("instance.canvas").croppie({
        viewport: { width: modImgWidth, height: modImgHeight },
        boundary: { width: modImgWidth, height: modImgHeight },
      	showZoomer: false,
      	enableResize: true,
      	enableOrientation: true,
      	enforceBoundary: true,
      	update: function (data) {

          	modImgWidth = $(".cr-viewport").width();
          	modImgHeight = $(".cr-viewport").height();

          	document.body.style.setProperty("--mat-width", modImgWidth + "px");
          	document.body.style.setProperty("--mat-height", modImgHeight + "px");
          	matHorzMargins = (instance.canvas.width() - modImgWidth) / 2;
  		  	document.body.style.setProperty("--mat-horz-margins", matHorzMargins + "px");
          	matVertMargins = (instance.canvas.height() - modImgHeight) / 2;
  		  	document.body.style.setProperty("--mat-vert-margins", matVertMargins + "px");

          	imgPoints = data.points;
          	imgZoom = data.zoom;
            console.log("zoom: " + data.zoom);
          	console.log("points.topLeftX: " + data.points[0]);
          	console.log("points.topLeftY: " + data.points[1]);
          	console.log("points.bottomRightX: " + data.points[2]);
          	console.log("points.bottomRightY: " + data.points[3]);
          	console.log(".cr-viewport.width: " + $(".cr-viewport").width());
          	console.log(".cr-viewport.height: " + $(".cr-viewport").height());
          	console.log("instance.canvas.width: " + instance.canvas.width());
            console.log("modImgWidth: " + modImgWidth + "px");
          	console.log("modImgHeight: " + modImgHeight + "px");
          	console.log("matHorzMargins: " + matHorzMargins + "px");
          	console.log("matVertMargins: " + matVertMargins + "px");

        $(".innermatte").on("click", function() {
    console.log("innermatte clicked");


And the update function:

function(instance, properties, context) {
instance.canvas.css("background", properties.defBGColor); // for testing, makes it easier to find the bubble canvas

      	modImgWidth = 510;
      	modImgHeight = 634;
// Load the image to get it's dimensions
/*	origImg = new Image(); 
 	origImg.src = properties.mat_image_url;
  	origImg.onload = function() {
      	modImgWidth = origImg.width / 2;
      	modImgHeight = origImg.height / 2; */

/*        widthDivider = origImg.width / properties.bubble.width; // get ratio of image width to container
    	heightDivider = heightDivider / properties.bubble.height; // get ratio of image height to container*/

  		matHorzMargins = ((properties.bubble.width - modImgWidth) / 2);
 		matVertMargins = ((properties.bubble.width - modImgHeight) / 2);
   //   imagetarget.croppie('destroy'); 
  imagetarget.croppie('bind', {
        orientation: 1,
    	zoom: imgZoom,
		points: imgPoints,
    	url: properties.mat_image_url
  	console.log("mat_image_url: " + properties.mat_image_url);
  	console.log("mat_color: " + properties.mat_color);
  	console.log("cut_width: " + properties.cut_width);
  	console.log("mat_shadow: " + properties.mat_shadow);
  	console.log("aspect_ratio: " + properties.aspect_ratio);
  	console.log("bubble.width: " + properties.bubble.width);
  	console.log("bubble.height: " + properties.bubble.height);
  	console.log("bubble.top: " + properties.bubble.top);
  	console.log("bubble.left: " + properties.bubble.left);
    console.log("matHorzMargins: " + matHorzMargins);
  	console.log("matVertMargins: " + matVertMargins);
   // console.log("widthDivider: " + widthDivider);
  	//console.log("heightDivider: " + heightDivider);
     // console.log("origImg.width: " + origImg.width);
  	//	console.log("origImg.height: " + origImg.height);
    console.log("modImgWidth: " + modImgWidth);
  	console.log("modImgHeight: " + modImgHeight);

  $(".innermatte").css("background-color", properties.mat_color);
  $(".innermatte").css("border-width", properties.cut_width + "px");
//  	document.body.style.setProperty("--box-shadow", properties.mat_shadow);
//  	document.body.style.setProperty("--mat-color", properties.mat_color);
//	document.body.style.setProperty("--cut-width", properties.cut_width + "px");
    document.body.style.setProperty("--mat-horz-margins", matHorzMargins + "px");
  	document.body.style.setProperty("--mat-vert-margins", matVertMargins + "px");
    document.body.style.setProperty("--mat-width", modImgWidth + "px");
    document.body.style.setProperty("--mat-height", modImgHeight + "px");
  $(".innermatte").css("border-bottom-color", properties.border_bottom_color);
  $(".innermatte").css("border-left-color", properties.border_left_color);
  $(".innermatte").css("border-top-color", properties.border_top_color);
  $(".innermatte").css("borrder-right-color", properties.border_right_color);

 if (properties.mat_shadow) {
//	document.body.style.setProperty("--box-shadow", "8px 10px 25px 5px rgba(0, 0, 0, 0.5) inset" );
   $(".innermatte").css("box-shadow", "8px 10px 25px 5px rgba(0, 0, 0, 0.5) inset");
} else {
//	document.body.style.setProperty("--box-shadow", "0px 0px 0px 0px rgba(0, 0, 0, 0.5) inset" );
  $(".innermatte").css("box-shadow", "0px 0px 0px 0px rgba(0, 0, 0, 0.5) inset");

// end of update function 
1 Like

I think that this var is the culprit! Calling variables this way will make them available to the whole page and then every next plugin’s element instance (each new image) will override the previous one.

Try creating it with

instance.data.newDiv =

That way it will be bound within the element’s instance. Just copy and paste it, no need to have anything before the instance.

See if it helps.

1 Like

Hi Vini,

That moved me on a lot but there is still a problem: While I can now get most of my parameters to be be unique anything that involves the divs created in:

instance.data.newDiv = $('<div id="innermatte"><img id="imagetarget"/></div>');

It hadn’t crossed my mind that this is also not unique. Do you know how I could maybe use the instance.data parameter in the id=imagetarget label so that each plugin instance creates a unique div id?

Or is there another way of doing this?

Create a unique id for each div instance.

Create a new field for the app maker to write an unique image name to be passed to the plugin, for example properties.passedImageName, then use that name as the image ID, maybe this will work:

instance.data.newDiv = $(`<div id="innermatte"><img id=${properties.passedImageName}/></div>`);

What I did: switched to ` and then put that variable as a string in the img id.

See if it works.

Edit: Considering what Sean said, if it works you can use the same mechanism to create a unique ID for the div instance.

I normally do something like this:
instance.data.divName = "id"+Math.round(Math.random()*1000000) + 1;

1 Like

you could just have the div, then for each image append it to the div. when you want to alter/remove/change an image you can select it by its src,

$("img[src='" + properties.imageURL + "']")

since the user will define the list of images that are really a list of urls, come time for a user to need to dynamically change one they can still ref. it by the url to fill the imageURL property.

If you require a div around each image, then you can access the div using the method above by adding,

$("img[src='" + properties.imageURL + "']").parent();

Thanks guys. Jarrad, that won’t work in this case since there can be multiple instances of the plugin in use at any one time. But you’ve sewn a seed for something else I need to do :slight_smile:

Edward, that’s a nice idea, I’ll give that a shot.

I need to give that one some thought. I’m not sure I want to leave the unique ID up to the plugin user. But I can see how that would work and I’ve learnt something from seeing how you would do that.

If you declare a single div tag save it on the instance, bring it down to the update function and start appending your images you will be fine with multiple elements.

Using the selector from above would still work though, as long as there is not more than one of the same url, then it may get messy.

Using a var is fine also - it wont effect other instances, the reason for this the code you write is actually inside a function making them confined to that function and not global. Easy one to test, write var a = 1; in the init function, then in the update function write, alert(a); - You will find that the alert will yeild undefined.

Consider this,

var div = $('<div>');
div.css({width: '100%', height: '100%'});
instance.data.div = div;

Then down in the update function -

var div = instance.data.div;

var goTime = $.each(properties.images.get(0, properties.images.length()), function (i, v) {
    var image = $('<img src="' + v.toString() + '">');
    //either perform your magic here on each image as you pump them out
    image.css({width: '100px', height: 'auto'});
    //if you prefer an ID, you can use the i parameter, What i would do is first i + 1 
   //so we don't have any images with an id using 0 & also count previous on page.
  //above you could give the image a class, eg. 
 //var image = $('<img class="myPlugin" src="' + v.toString() + '">');
//then something like this,
//var id = 'image-' + (i + 1 + $('.myPlugin').length);
//var image = $('<img id="' + id + '" class="myPlugin" src="' + v.toString() + '">');

//or you can process them all once they are done
var allInstanceImages =  $(div).find('img');
$(allInstanceImages).css('cursor', 'pointer');

instance.data.div = div;

Now looking at say a change this image action -

var div = instance.data.div;
$(div).find("img[src='" + properties.imageURL + "']").css({width: '50%', height: '50%'});
//because we brought the saved instance down, and we are running our 
//find only inside this instance, then you will not interfere with other instances.
instance.data.div = div;

Just thought I would drop this method here aswell as it could save you changing any code. This would be better suited to the one image per element scenario.

Use the same init function from above but make the update something like this -

var div = instance.data.div;

$(div).html('<img src="' + properties.img + '">');

//This method is good because any change to your //properties will run the update function and 
//rerender this element to reflect the change.

instance.data.div = div;

Guys, I’ve implemented a mix of your ideas and it’s working well now. More than that I’ve learnt a thing or two, so I’m very grateful. Thanks all!

1 Like

This topic was automatically closed after 70 days. New replies are no longer allowed.