calling inner function of plugin - jquery-plugins

Here is my plugin
(function($){
$.fn.myPlugin = function(options){
var defaults = {
width: 800
};
var defaults = $.extend(defaults, options);
var self = this;
function init(obj){
/*Initialize object*/
self.myPlugin.doAnimation(600,400);
}
$.fn.myPlugin.doAnimation = function(lV, rV){
/*Doing some animation work*/
}
return this.each(function(options){
init(this);
});
}
})(jQuery);
I am trying like this
var t = $('#id1').myPlugin();
t.doAnimation(); //getting error here, t.doAnimation is not a function

You can't. You're not returning the plugin. You're returning the jQuery object with the matched element(s) (like you probably should). The testing function is private to the myPlugin function anyway.
To call a method against a jQuery object, you would need to extend jQuery like you did for your myPlugin(), as in:
function($){
$.fn.myPlugin = function(options) {
...
}
$.fn.testing = function(options) {
...
}
})(jQuery);
Of course this would be completely separate from the original plugin.
I don't know what your plugin does, but if you need to share some data between plugins on a per-element basis, you could probably use jQuery's .data() method.

Related

jQuery Plugin prototype with addons

I create a free jQuery plugin and what I would like to do is to create some add-ons that will be able for my clients under payment.
So, let's suppose that the free jQuery plugin that I offer for free append hello world into an html div tag and I would like to create an add-on that makes the div background color red.
Free Version of plugin:
(function(window, $) {
var example = function(elem, options) {
this.elem = elem;
this.$elem = $(elem);
this.options = options;
this.metadata = this.$elem.data('example-options');
};
example.prototype = {
defaults: {
message: 'Hello world!'
},
init: function() {
this.config = $.extend({}, this.defaults, this.options, this.metadata);
this.displayMessage();
return this;
},
displayMessage: function() {
this.$elem.append('<h1>'+this.config.message+'</h1>');
}
}
example.defaults = example.prototype.defaults;
$.fn.example = function(options) {
return this.each(function() {
new example(this, options).init();
});
};
window.example = example;
})(window, jQuery);
And I would like to create an addon that will be in a different js file, like this:
example.prototype = {
bgColor: function() {
this.$elem.css('background-color', '#f00');
}
};
How can I do this?
Rather than replacing the default prototype that you have created, simply add to it and override methods that you wish to change. For example, you can add your bgColor method to the prototype as follows:
example.prototype.bgColor = function() {
this.$elem.css('background-color', '#f00');
};
To override methods to provide enhanced functionality, you can do the same:
example.prototype.displayMessage = function() {
this.$elem.append('<h1>This message comes from the add-on</h1>');
}
Note that for this to work, the add-on js file is included after the default plugin js file.

Jasmine testing, using a constructor in the beforeEach

i am attempting to create a new instance of two classes that i have already written in separate files. when i try to create new instances of them in the beforeEach() section of the test code, the tests return undefined for my newly created objects. however when i create them in each IT section the test run perfectly.
describe("placeStone", function() {
beforeEach(function() {
var go = new Display();
var logic = new Internals(go);
logic.tempBoard = [ array];
});
it("should place a black stone at 0,6", function() {
logic.placeStone(logic.black,0,6);
expect(logic.tempBoard[6][0]).toEqual("B");
});
this returns logic undefined.
describe("placeStone", function() {
it("should place a black stone at 0,6", function() {
var go = new Display();
var logic = new Internals(go);
logic.tempBoard = [ array];
logic.placeStone(logic.black,0,6);
expect(logic.tempBoard[6][0]).toEqual("B");
});
});
this seems to work the way i want. how can i get it to work in the beforeEach() section?
var logic should be defined in the scope of the describe function, then it exists both in the scope of the beforeEach function and the spec (the it function), e.g.
describe('suite', function () {
var myVar;
beforeEach(function(){
myVar = 10;
});
it('checks myVar', function () {
expect(myVar).toEqual(10);
});
});

Knockout predefined default with options binding to observable array

I am getting a list of options for a select from a server and populating an observableArray. Then I would like to set the selected item to a predefined value. I have a very simple jsFiddle that emulates pulling data from a server with a button click.
http://jsfiddle.net/JonathanN/hev1rqeu/
Here's the Javascript with the basic attempt:
(function() {
var vm = (function() {
var self = this;
self.array = ko.observableArray([]);
self.selectedValue = ko.observable();
self.useSetTimeout = ko.observable(false);
self.array.subscribe(function(newValue) {
self.selectedValue('b');
});
self.populate = function() {
self.array(['a','b','c']);
};
}());
ko.applyBindings(vm);
}());
And here's my workaround, which replaces "self.selectedValue('b');":
var waitForSelectToPopulate = function() {
self.selectedValue('b');
if(self.selectedValue() != 'b') {
setTimeout(waitForSelectToPopulate, 10);
}
};
waitForSelectToPopulate();
I am not very fond of this as a workaround. It seems like there should be a reasonable way to handle this, but just setting the value on subscribe trigger doesn't seem to work.
You need optionsAfterRender. Here's a fiddle:
http://jsfiddle.net/sifriday/hev1rqeu/4/
HTML -
<select data-bind="options: array, value: selectedValue, optionsAfterRender: setVal">
JS addition -
self.setVal = function() {
self.selectedValue('b');
}
Docs - http://knockoutjs.com/documentation/options-binding.html - and scroll down to Note 2
Once the populate event has gone and got the json and placed it into your array, why not just set the value right after? as soon as you set the data inside of self.array it will update.
(function() {
var vm = (function() {
var self = this;
self.array = ko.observableArray([]);
self.selectedValue = ko.observable();
self.populate = function() {
// magical assmagic goes and get's json, and converts it to ['a','b','c']
self.array(['a','b','c']); // dropdown is now populated
self.selectedValue('c'); // therefore we can set it to a valid value
};
}());
ko.applyBindings(vm);
}());
see the following:
http://jsfiddle.net/hev1rqeu/5/

backbone console log event triggering

I've got a underscore/backbone/require application and I would like to output all events that are triggered through backbone to the console (in other words: pass each event through console.log function). I've tried wrapping it with underscore and manually replacing the function. Neither this:
console.log(Backbone.Events.trigger);
var trigger = Backbone.Events.trigger;
Backbone.Events.trigger = function(name) {
console.log('Event', name, 'triggered.');
trigger.apply(this, arguments);
}
nor this:
Backbone.Events.trigger = _.wrap(Backbone.Events.trigger, function(func) {
console.log('EVENT:', Array.prototype.slice.call(arguments));
func(Array.prototype.slice.call(arguments));
});
console.log(Backbone.Events.trigger);
worked. I'd appreciate a javascript (not coffeescript) solution.
Your wrappings fail because Backbone mixes in Backbone.Events behavior on Backbone.Model, Backbone.Collection, etc. For example, Backbone.Model is defined as
var Model = Backbone.Model = function(attributes, options) {
...
};
_.extend(Model.prototype, Events, {
...
};
This means that when you redefine Backbone.Events.trigger, it is already too late.
But all is not lost! You won't be able to redefine all trigger methods in one go, but you can redefine them on class level:
Backbone.Model.prototype.trigger = function() {
console.log('Event', arguments);
Backbone.Events.trigger.apply(this, arguments);
}
and a demo http://jsfiddle.net/nikoshr/G2Qfn/
For a given class, you can override the trigger method:
var M = Backbone.Model.extend({
trigger: function() {
console.log('Event', arguments);
Backbone.Model.prototype.trigger.apply(this, arguments);
}
});
http://jsfiddle.net/nikoshr/G2Qfn/1/
or for a given instance
var M = Backbone.Model.extend({});
var m = new M();
m.trigger = function() {
console.log('Event', arguments);
M.prototype.trigger.apply(this, arguments);
}
http://jsfiddle.net/nikoshr/G2Qfn/2/

External handlebars templates backbone marionette

In my application i added Marionette.sync plugin and override these methods:
Backbone.Marionette.TemplateCache.prototype.loadTemplate = function (templateId, callback) {
var tmpId = templateId.replace("#", ""),
url = "/app/templates/" + tmpId + ".html";
$.get(url, function (templateHtml) {
compiledTemplate = Handlebars.compile($(templateHtml).html())
callback.call(this, compiledTemplate);
});
};
Backbone.Marionette.Renderer.renderTemplate = function (template, data) {
template(data);
};
But this not work, any ideas?
I assume you're running v0.9 of Marionette since you mention the Marionette.Async plugin.
The Renderer change is slightly off in the method name, and nothing is calling your TemplateCache object anymore.
If you're intending to use pre-compiled Handlebars functions, then you only need to do this:
Backbone.Marionette.Renderer.render = function(template, data){
return template(data);
};
If you intend to have the template loaded asynchronously and then compiled, using the TemplateLoader, your code would need to look like this:
Backbone.Marionette.TemplateCache.prototype.loadTemplate = function (templateId, callback) {
var tmpId = templateId.replace("#", ""),
url = "/app/templates/" + tmpId + ".html";
$.get(url, function (templateHtml) {
compiledTemplate = Handlebars.compile($(templateHtml).html())
callback.call(this, compiledTemplate);
});
};
Backbone.Marionette.Renderer.renderTemplate = function (templateId, data) {
var renderer = $.Deferred();
Backbone.Marionette.TemplateCache.get(templateId, function(template){
var html = template(data);
renderer.resolve(html);
});
return renderer.promise();
};
The Renderer is responsible for calling the TemplateCache.
Side note: what article / blog post / wiki page / documentation were you using to get your code from? I have probably missed some pages that need to be updated.

Resources