The First Pattern: "Module Pattern" AFAIK
We have a pretty common pattern for using plupload. We don't use their built in UI because it is overkill for our simple single uploads. So we declare our own HTML
<div class="control-group">
<label class="control-label" for="OriginalFilename">Attachment (optional):</label>
<div class="controls">
<div id="uploadControl">
<a id="pickfiles" class="btn btn-default" href="@Url.Void()">Select</a>
<div id="filelist">Your browser doesn't have Flash, Silverlight or HTML5 support.</div>
</div>
@Html.Hidden("TemporaryFilename")
@Html.Hidden("OriginalFilename")
<span class="help-inline error">
@Html.ValidationMessage("OriginalFilename")
</span>
</div>
</div>
and then initialize plupload wiring up events to the button and populating the hidden fields with upload results.
There is alot of repetition each time we implement this on the javascript side, so I implemented a module pattern to put the common code in. Leveraging the module looks like this, so you just put this at the bottom of your page, telling the module what url to upload to, and it exposes an upload started and upload succeeded events.
pluploadBuilder.init({
chunkUrl: '/SubmissionFileChunker")',
maxFileSize: '25mb',
uploadStarted: function () { $('#submitBtn').attr('disabled', 'disabled'); },
success: function () { $('#submitBtn').removeAttr('disabled'); },
filenameResultSelector: '#TemporaryFilename',
browseButtonId: 'pickfiles'
});
My module pattern looks like this, but you can see how I'm taking the config values passed in and using them to initialize plupload:
var pluploadBuilder = (function (){ //Module pattern
return {
init : function(config) {
var self = this;
var uploader = new plupload.Uploader({
runtimes: 'html5,flash,silverlight,html4',
browse_button: config.browseButtonId,
url: config.chunkUrl,
FileUploaded: function (up, file, info) {
$(filenameResultSelector).val(info.response);
if (config.hasOwnProperty('success'))
config.success();
},
//...many more plupload events, omitted for brevity...
});//end plupload
uploader.init();
},//module init
}
}());
The problem with this is as far as I understand this construct, is it is a singleton, and thus this will not work if I need to do this more than once on a page. I.e. if I have two seperately declared html blocks, and want to initialize each, the main challenge being that each upload should populate its respective hidden fields. Imagine a dynamically generated form that presents several items with a form for each.
I can't use ID selectors anymore unless I want to hack it with some crazy ID generator Id='TemporaryFilename-123' since there will be multiple '#TemporaryFilename' fields.
The Second Pattern: Name unknown
How I've handled this in the past is to use a pattern like this to scope all selectors to a parent container and select on classes instead of Ids:
var uploadBuilderNS = function ($this) { //$this expected to be a container element(already jquery selected)
var initialize = function (config) {
//similar plupload initialization except we scope selectors to $this, and caller should be using class selectors like: filenameResultSelector: '.tempFilename':
var uploader = new plupload.Uploader({
...
FileUploaded: function (up, file, info) {
$this.find(config.filenameResultSelector).val(info.response);
if (config.hasOwnProperty('success'))
config.success();
},
});
uploader.init();//calling pluploads init(not our init)
};
return {
initialize: initialize,
};
};
Then you would leverage like this assuming each control group was in a .uploadContainer:
$(".uploadContainer").each(function () {
uploadBuilderNS($(this)).initialize({ filenameResultSelector: '.temporaryFilename',... });
});
Basically I went through a few module pattern articles and came up with the first solution thinking I was refining my pattern. However, now that I understand exactly what is happening, it doesn't seem very modular at all. It is pretty much a singleton and I don't see how it would scale well for anything other than static utility/helper functions. I'm not sure what the second pattern, the old one I had been using previously is called, but it certainly seems more modular than the first. I guess that is the pitfall of people promoting a pattern without explaining its purpose. No pattern is universal and has appropriate uses, but I had seen it promoted quite a bit so I thought it would be an improvement upon what I had been doing previously. Please don't flame me. Maybe I'm using it wrong, obviously I realize this or else I wouldn't be here! I'm just explaining my understand so far so others can point out where I might be confused.
What is the second pattern called? I've seen it referred to in a couple places as a module pattern, but it is significantly different from the first, in that each uploadBuilderNS($(this)) generates a new instance. My main goal originally was to look at what others were suggesting, since it seems these patterns have been refined over time. I feel like I went down a really wrong path by switching to the first module pattern now that I realize it is a singleton.
Is there a more appropriate pattern for handling initializing multiple controls?
Update:
Problem with calling the first multiple times is element selectors being ID based and not being scoped to a container. If there are multiple controls repeated with the same IDs this won't work. I can switch to class selectors, but I still need a container element to scope to. The second pattern deals with this by passing in a container element to the closure when constructing each instance(see the last code block). The first pattern doesn't allow for this because it is constructed as soon as the script is loaded, so a parameter like var pluploadBuilder = (function (container){ wouldn't work since a parameter there is only for imports(i.e. it runs/creates the singleton when the script is loaded, and I have no opportunity to create multiple pluploadBuiler's passing in different containers): http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
The only way I can invision making the first pattern work with calling initialize multiple times is to generate sequential ID suffixes when rendering the HTML, such as "TemporaryFilename-123". But this will be much more messy. If you look at the last codeblock, initializing multiple instances is much cleaner with the second pattern. No need to use IDs as it is purely class based selectors, and the foreach/init allows me to initialize multiple identical control groups with one code block.
thiswithininit? This question cannot be properly answered without that knowledge.thiswhat prevents you from callingpluploadBuilder.initmultiple times with a different configuration?pluploadBuilder.initis just a factory function. Nothing prevents you from doingpluploadBuilder.init({ container: someEl, ... });. You actually do not need thepluploadBuilderobject at all (only serving as a namespace here). I would rather just have a function likefunction createUploader(config). If you would however, store data onthis, then you could doObject.create(pluploadBuilder).init(config).