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

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}

Related

How to properly reset angularjs v1 factory after certain function

I Made a factory that keeps the information in my scopes in a series of 6 pages. Now when the user completes the 6th page and pushes the object I want the factory to reset to empty arrays again.
I already tried a lot with the timeout and apply elements, also tried a lot of combinations to set the array to empty (null, "", {}). but it still loads the old information when I load the page again(page 1/6).
The submit function (That also needs to reset the scopes) is
$scope.send = function(){
if(ArrayInfo.Checkmark == true){
firebase.database().ref('lorem/' + ArrayInfo.Ordernumber).set({
info: ArrayInfo,
Dates: Dates,
gasmeter: gasmeter,
gasmeter1: gasmeter1
}).then(function(){
firebase.database().ref('lorem2/' + ArrayInfo.currentYear).set({
last_number: ArrayInfo.Ordervalue
});
}).then(function(){
//ArrayInfo = {};
setTimeout(function(){
ArrayInfo = "";
$scope.info = "";
$scope.$apply();
$scope.$digest();
}, 50);
});
//close newrental
setTimeout(function(){
if (window.confirm('Information saved! You are ready to leave this screen? no changes possible after this point'))
{
//disable back button in home
$ionicHistory.nextViewOptions({
disableBack: true
});
//go home
$state.go("app.auth");
}
//error close newrental
else
{
alert("Take your time");
}
}, 50);
}
//error send array
else {
alert("Please accept the terms and conditions.");
}
}
My factory looks like this
mainapp.factory("infoFactory", function(){
ArrayInfo = {};
placeholders = {
"licenseone" : "img/placeholder.png",
"licensetwo" : "img/placeholder.png",
"licensethree" : "img/placeholder.png",
"licensefour" : "img/placeholder.png",
"imageone" : "img/front.png",
"imagetwo" : "img/sideleft.png",
"imagethree" : "img/back.png",
"imagefour" : "img/sideright.png",
"imagefive" : "img/roof.png",
"imagesix" : "img/placeholder.png",
"imageseven" : "img/placeholder.png",
"imageeight" : "img/placeholder.png"
};
gasmeter = {
"url" : "img/gas/gas1.png",
"gasvalue" : "1"
}
gasmeter1 = {
"url" : "img/gas/gas1.png",
"gasvalue" : "1"
}
ArrayInfo.returned = false;
RawDate = {};
Dates = {};
console.log(ArrayInfo);
return ArrayInfo;
return gasmeter;
return gasmeter1;
return placeholders;
return RawDate;
return Dates;
})
and I load the information in my controller like this
$scope.info = infoFactory;
$scope.Dates = Dates;
$scope.RawDate = RawDate;
$scope.gasmeter = gasmeter;
$scope.gasmeter1 = gasmeter1;
The angular version I am using is "3.6.6"
First of all, when you put return in your code, there's no use to include additional code after that, because it will never run. You need to return an Object instead.
mainapp.factory("infoFactory", function(){
ArrayInfo = {};
placeholders = {
"licenseone" : "img/placeholder.png",
// Rest of the images
};
gasmeter = {
"url" : "img/gas/gas1.png",
"gasvalue" : "1"
}
gasmeter1 = {
"url" : "img/gas/gas1.png",
"gasvalue" : "1"
}
ArrayInfo.returned = false;
RawDate = {};
Dates = {};
console.log(ArrayInfo);
return {
ArrayInfo: ArrayInfo,
gasmeter: gasmeter,
gasmeter1: gasmeter1,
placeholders: placeholders,
RawDate: RawDate,
Dates: Dates
};
})
Now you can inject infoFactory to the controller and use it like this: infoFactory.RawDate.
Now, if you want to reset the factory, you can add a function that reset all the data:
mainapp.factory("infoFactory", function(){
// Save a reference to the current pointer of the factory, so you won't loose it inside other scopes
var self = this;
self.params = {
ArrayInfo: {},
placeholders: {},
gasmeter: {},
gasmeter1: {},
ArrayInfo: false,
RawDate: {},
Dates: {}
};
self.reset = function() {
self.params.ArrayInfo = {};
self.params.placeholders.licenseone = "img/placeholder.png";
self.params.gasmeter.url = "img/gas/gas1.png";
self.params.gasmeter.gasvalue = "1";
self.params.gasmeter1.url = "img/gas/gas1.png";
self.params.gasmeter1.gasvalue = "1";
self.params.ArrayInfo.returned = false;
self.params.RawDate = {};
self.params.Dates = {};
}
self.reset(); // Call this function by default in order to initially set the factory properties
return {
reset: self.reset, // You can export the reset function and use it outside the factory too
ArrayInfo: self.params.ArrayInfo,
gasmeter: self.params.gasmeter,
gasmeter1: self.params.gasmeter1,
placeholders: self.params.placeholders,
RawDate: self.params.RawDate,
Dates: self.params.Dates
};
})
Now when you have a reset function, you can use it like this outside the factory: infoFactory.reset() whenever you want to reset the data to the initial state. I created inside the factory a base object (this.params = { .. }) and saved inside it all the details properties, inside the reset function I have updated those properties without breaking the original references (Working example).
The above is just an example, but you can (or perhaps should) encapsulate the params of the factory, and only allow the user to control and change the values via helper functions. Example of how to do it:
mainapp.factory("infoFactory", function(){
var self = this;
self.params = {
returned: false,
};
return {
setReturned: function(val) { self.params.returned = val === true; },
returned: function() { return self.params.returned; }
}
});
The above example will hide the actual params.returned from the user outside the factory, and only allow it to set the returned flag via helper function, i.e infoFactory.setReturned( true ); or infoFactory.setReturned( false );, and inside that setReturned function you can implement complex logic to validate the value sent to the function. Note that infoFactory.setReturned( 'invalid value!!!' ); will set the returned flag to false since i'm validating the value using the strict === operator - val === true.
Then, to get the value from the factory you call the infoFactory.returned() function - By using a function you're blocking outside access to the properties of the factory.
As a side note - Don't use setTimeout(function(){ ... }); Use $timeout and $interval and then you won't need $scope.$apply(); + $scope.$digest(); in order to manually run a digest cycle because it is being handeled nativaly by Angularjs for you

How can I extend Backbone.history.navigate?

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 );

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>

jquery fn.extend() returning values and call values in object

I need some help in understanding something, that propably is easy for serious jquery and javascript programmers.
Lets say I have a code like this:
jQuery.fn.extend({
myNameSpace: {
myPlugIn: function (o) {
var o = { variable : o.variable || false };
var myfunction = function(v) {
o.variable = v;
};
return {
myfunction : myfunction
};
}
});
and now I am able to call that with:
x = new $.myNameSpace.myPlugIn({variable : 99}) ;
and then I call my function myfunction like this
x.myfunction(20);
I can understand that, now the question: how can I get the value of variable inside my plug in.
I tried something like alert(x.o[variable]); etc. but I just cant get it - It must be easy...
What I try to accomplish is a value I could call if something inside the plugin is finished, or calculated.
You can not get the variables inside with your current code, unless you change it to:
var myfunction = function(v) {
o.variable = v;
return v; //or o.variable
};
//...
x.myfunction(20) //20;
Added
It seems like you are trying to make a plugin for jQuery. To create a plugin, you do not use $.extend. $.extend is only used to preset default settings. [1] Normally this is how you set up a plugin:
(function($) {
var methods = {
getVar: function(){
return $.extend({
data: data,
}, methods);
},
setVar: function(d){
data = d;
return methods;
}
},
data = {};
$.fn.myPlugin = function(options) {
//do stuff
data = $.extend( data , options );
return methods;
};
})(jQuery);
http://jsfiddle.net/DerekL/wv5QH/1/

Categories