How can I extend Backbone.history.navigate? - javascript

When I call Backbone.history.navigate, I want to be able to change a global variable.
I want to set
window.linkclicked = true; // when someone clicks a link
and
window.linkclicked = false; // when back button is pushed.
Is there a way to do this using javascript prototypes?
How do I insert that logic inside the "navigate" method?

You can extend the Backbone.history instance and just redefine the navigate function as you wish.
var originalNavigate = Backbone.history.navigate;
_.extend(Backbone.history, {
navigate: function(fragment, options) {
// do stuff before
var returnValue = originalNavigate.apply(this, arguments);
// do stuff after
return returnValue;
},
});
Or with the closure module pattern:
Backbone.history.navigate = (function(navigate) {
return function(fragment, options) {
/* ...snip ...*/
}
})(Backbone.history.navigate);

You can extend the functionality with underscore:
_.extend(Backbone.history.navigate, {
linkClicked : function( bool ){
//handle link clicked
}
});
You can call this with:
Backbone.history.navigate.linkClicked( true );
//or
Backbone.history.navigate.linkClicked( false );

Related

Extend jQuery Plugin with additional function / override function

I need to extend a jQuery Plugin (https://github.com/idiot/unslider) in order to add additional behavior with another public method.
(function(){
// Store a reference to the original remove method.
var originalMethod = $.fn.unslider;
// Define overriding method.
$.fn.unslider = function(){
// Execute the original method.
originalMethod.apply( this, arguments );
console.log( "Override method" );
function test() {
console.log("test called");
}
this.each(function() {
// Operations for each DOM element
console.log("each dom element?");
}).data('unslider', {
// Make test accessible from data instance
test: test
});
return this;
}
})(jQuery);
I already managed to make the public method accessible when calling
var slider = $('#slider');
slider.data('unslider').test();
However, I want to keep the old behavior of unslider anyways, but extend the Plugin with another function. Does anyone have an idea?
I created a fiddle, so you can check whats happening:
My new function gets called, but the old ones are gone:
http://jsfiddle.net/b2os4s7e/1/
If you look at the source of unslider, you can see it stores the Unslider instance inside the data:
// Enable multiple-slider support
return this.each(function(index) {
// Cache a copy of $(this), so it
var me = $(this),
key = 'unslider' + (len > 1 ? '-' + ++index : ''),
instance = (new Unslider).init(me, o);
// Invoke an Unslider instance
me.data(key, instance).data('key', key);
});
In your code you're overwriting this object with your own object. However, the slider expects there to be an Unslider instance. So what you want to do is get this instance and then extend it with your own functions:
var key = $(this).data('key');
var obj = $(this).data(key);
obj.test = function() { console.log('Working!'); };
See http://jsfiddle.net/b2os4s7e/2/
Just define:
$fn.unslider2 = function() { ... }
With any name and behaviour you like.
For extend JQuery should use .fn.extend
(function($){
$.fn.extend({
helloworld: function(message){
return this.each(function(){
$(this).click(function(){
alert(message);
});
});
}
});
})(jQuery)
the object .fn.extend is used for extend funcionality of jQuery
Thanks for your answers! I did it this way:
(function($){
var originalMethod = $.fn.unslider;
$.fn.extend({
unslider: function(o) {
var len = this.length;
var applyMethod = originalMethod.apply( this, arguments );
var key = applyMethod.data('key');
var instance = applyMethod.data(key);
// Cache a copy of $(this), so it
var me = $(this);
if (instance) {
instance.movenext = function (callback) {
return instance.stop().to(instance.i + 1, callback);
};
instance.moveprev = function (callback) {
return instance.stop().to(instance.i - 1, callback);
};
}
return applyMethod.data(key, instance);
}
});
})(jQuery)
The key was to address the data attribute as sroes suggested.
Moreover i needed to apply the original method, since i need the old methods.

How to call a function's methods from within another function

In the form object below, from within the "check" function, how do I call the "show" and "hide" methods of the notification function?
(function (namespace, $, undefined) {
var form = {
check : function(){
form.notification.show(); // Generates an error
},
notification : function(){
this.show = function(){
...
};
this.hide = function(){
...
};
}
};
}(window.namespace = window.namespace || {}, jQuery));
With form.notification.show() I get the following error:
Uncaught TypeError: Cannot read property 'show' of undefined
Try to define notification outside form and then refer to it:
var notification : { // no function here
show : function(){...}, // avoid "this"
hide : function(){...}
};
var form = {
check : function(){
notification.show(); // <-- Use here
},
notification : notification // and here
};
(I omitted the jQuery protection code for clarity).
The next problem is that you this.show = will assign the function to whatever this is when the function notification() is executed. this isn't notification!
You've enclosed it, so you need to return it and that will expose it for you, if you whip the following in chrome console, you'll see you have access to the form object
(function (namespace, $, undefined) {
var form = {
check : function(){
form.notification.show(); // Generates an error
},
notification : function(){
this.show = function(){
};
this.hide = function(){
};
}
};
return{form:form};}(window.namespace = window.namespace || {}, jQuery));
All i've done to your code is added
return{form:form};
After the form object. Hope this helps
EDIT
If you want to only expose certain parts of the form, for example only notifications, you could modify the return like so:
return{form.notification: notification}

JavaScript calling a getter from its function

Trying to do something that in pseudo code would look like this:
(function(scope) {
scope.doSomenthin = function() {
if (x === y && this.onfinish) {
// If exists, run onfinish, should return 'fin'
this.onfinish();
}
}
})(scope);
window.scope = window.scope || (window.scope = {});
scope.doSomenthin().onfinish = function(){return 'fin'}
At run time if onfinish exists, run that function. Tried using getters/setter but at that point it will return undefined. Setting a timeout works but its not something I wish to do.
Any other ideas? Thanks.
I'm not sure if I completely understand the question, but I think what you want comes down to setting the context for the functions you are calling. Is this what you are after?
//create a function that accesses an object's properties and methods with 'this'
var doSomethin = function() {
var result = "nonfinish";
if (this.onfinish) {
// If exists, run onfinish, should return 'fin'
result = this.onfinish();
}
return result;
}
//add an 'onfinish' method to the 'scope' object
scope = {
onfinish: function(){return 'fin'}
}
//run the accessor function in the window context
alert(doSomethin());
//run the accessor function in scope's context
alert(doSomethin.call(scope));
I see several mistakes with your code. This may be the results you are trying to achieve..
window.scope = window.scope || (window.scope = {});
scope.onfinish = function(){return 'fin'};
(function(scope) {
scope.doSomenthin = function() {
if (this.onfinish) {
// If exists, run onfinish, should return 'fin'
return this.onfinish();
}
}
})(scope);
alert(scope.doSomenthin());
When you create the temporary scope here you give scope as a
parameter. But scope is not defined yet.
(function(scope) {
scope.doSomenthin = function() {
if (x === y && this.onfinish) {
// If exists, run onfinish, should return 'fin'
this.onfinish();
}
}
})(scope);
Your scope.doSomenthin function doesn't return any value. Because
of that the value of scope.doSomenthin() is undifined. Therefore
with scope.doSomenthin().onfinish = function(){return 'fin'} you
are trying to set a property of undifined.
What you want to approach is similar to event-driven programming. Don't just call the function right away, register it as an event handler instead. The following pseudo-code only shows my idea. It's not complete
//register the function here, instead of calling it immediately
event = document.createEvent("HTMLEvents");
event.initEvent("myEvent", true, true);
document.addEventListener("myEvent", function(e) {
e.scope.doSomenthin = function() {
if (this.onfinish) {
// If exists, run onfinish, should return 'fin'
return this.onfinish();
}
}
});
......
//call the handler to handle the below event
window.scope = window.scope || (window.scope = {});
scope.doSomenthin().onfinish = function(){return 'fin'}
event.scope = scope;
document.body.dispatchEvent(event);
The above code is kind of silly. You have to design where to put and trigger the events.

Accessing public functions from inside a jQuery plugin

It is the first time I write a jQuery plugin without a tutorial. Now (September 28 2014), the jQuery site doesn't work (I don't know why), so I cannot find any resource there.
Below is part of my plugin that reports errors:
$(function($){
$.fn.dialog = function(command, options) {
var opts = $.extend( {}, $.fn.dialog.defaults, options );
//code
$.fn.dialog.handleCancel = function() {
};
$.fn.dialog.handleAccept = function() {
};
return this;
};
$.fn.dialog.defaults = {
// some other props
onCancel: $.fn.dialog.handleCancel(),
onAccept: $.fn.dialog.handleAccept()
};
// code
}(jQuery));
When I call the plugin ($("#dialog1").dialog(/*..*/)), the browser console, shows the following:
Uncaught TypeError: undefined is not a function
The error is on the line with onCancel: $.fn.dialog.handleCancel().
How can I access these methods, and where should them be? (I also want them to have access to $(this) <- for the dialog itself)
Your handleCancel and handleAccept functions are not initialized until you call the $.fn.dialog function. Therefore, they are undefined when you set the dialogs defaults.
Insert this code prior to $.fn.dialog.defaults:
$.fn.dialog();
Try rearranging blocks within the piece , adding a filter , to prevent both handleCancel and handleAccept being called by default; e.g.,
(function($){
$.fn.dialog = function(command, options) {
var $el = this;
// access , pass arguments to methods
$.fn.dialog.handleCancel = function(c) {
$el.html(c + "led")
};
$.fn.dialog.handleAccept = function(a) {
$el.html(a + "ed")
};
// call `handleCancel` or `handleAccept` ,
// based on `command`
$.fn.dialog.defaults = {
// some other props
onCancel: command === "cancel"
? $.fn.dialog.handleCancel(command)
: null,
onAccept: command === "accept"
? $.fn.dialog.handleAccept(command)
: null
};
var opts = $.extend( {}, $.fn.dialog.defaults, options );
//code
return this;
};
// code
}(jQuery));
$("button").on("click", function(e) {
$("#result").dialog(e.target.id)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button id="accept">accept</button><button id="cancel">cancel</button><br />
Result: <div id="result"></div>

Overriding a function in jQuery plugin

I have an existing jQuery plugin, now I want to extend it. Consider the below mentioned plugin:
$.fn.x = function(option) {
var def = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
//do something
}
function def() {
//do something
}
};
Now the above one is the plugin I got from somewhere. I need to have custom behavior for abc method, say
function abc() {
//do something else
}
I don't want to change the existing plugin, Can you tell me how could I achieve the same by extending the same or by making my own custom plugin ?
EDIT:
I tried this too with method mentioned below:
(function($) {
$.fn.x = function(option) {
var defaults = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
//do something
console.log('Base method called');
}
function def() {
//do something
abc();
}
def();
};
})(jQuery);
(function() {
var x = $.fn.x;
$.fn.x.abc = function() {
console.log('Overidden method called');
//_x.abc();
};
})();
$('<div/>').x();
But I am still getting "Base method called" as the console output.
The best route can vary, but something that I've done in the past is to wrap the extension in my own! This works best when you're trying to operate on something that the plugin does without modifying its underlying code.
(function($){
$.fn.extendedPlugin = function(options) {
var defaults = {
//...
};
var options = $.extend(defaults, options);
//Here you can create your extended functions, just like a base plugin.
return this.each(function() {
//Execute your normal plugin
$(this).basePlugin(options);
//Here you can put your additional logic, define additional events, etc
$(this).find('#something').click(function() {
//...
});
});
};
})(jQuery);
I know this isn't terribly specific (it's hard without a specific scenario), but hopefully it'll get you started down the right path!
This is as far as I got. But when I uncomment _x.abc.apply( this, arguments );, it gets stuck in a recursive loop.
Here's the jsfiddle if someone wants to play with and fix it:
http://jsfiddle.net/TLAx8/
// PLUGIN DEFINITION
(function( $ ){
$.fn.x = function(option) {
var def = {
a: 1,
b: 2
};
option = $.extend(def, option);
function abc() {
console.log( 'Plugin method called' );
}
function def() {
//do something
}
};
})( jQuery );
// OVERRIDING THE PLUGIN METHOD
(function(){
var _x = $.fn.x;
$.fn.x.abc = function() {
console.log( 'Overidden method called' );
//_x.abc.apply( this, arguments );
}
})();
// INVOKING THE METHOD
(function() {
$.fn.x.abc();
});

Categories