Nested functions have no access to requirejs callback parameters - javascript

While migrating to requirejs I have run into a problem that I cannot seem to find the answer to.
The problem is that my nested functions do not have access to the parameters passed to the requirejs callback.
for example:
define(['knockout', 'knockoutmapping', 'other'], function(ko, mapping, other) {
var Something = function() {
var self = this;
self.items = ko.observableArray([]);
self.doSomeStuff = function(data) {
// I would think I would still be able to access
// parameters ko, mapping and other
// trouble is, I cannot. I only have
// a valid 1st parameter, "ko".
var d = ko.toJSON(self.items()); // this works fine
self.items(mapping.fromJS(data));// this does not work (undefined)
// do not have access to "other" either.
};
};
return {
Something: Something,
};
});
Any help with this would be appreciated. I know I could put these into variables in the callback, but that doesn't seem like the correct approach to me.
Thank you in advance.

in define, callback is first argument and it have one parameteter require function, try:
define(function(require) {
var knockout = require('knockout');
var knockoutmapping = require('knockoutmapping');
var other = require('./other');
var Something = function() {
...
};
return {
Something: Something,
};
});

Related

Function chaining with function names from list [duplicate]

What is the equivalent code of window["functionName"](arguments) in NodeJS server-side?
If you need such a capability within a module, one hack is to store such module functions in variables within the module and then call them by accessing them from the module object properties. Example:
var x = { }; // better would be to have module create an object
x.f1 = function()
{
console.log('Call me as a string!');
}
Now, within the module, you can call it using the value from a string:
var funcstr = "f1";
x[funcstr]();
I am learning the ropes with Node myself, the above is probably all sorts of wrong :-). Perhaps a marginally better way to write this example would be (for the module m.js):
module.exports =
{
f1: function() { console.log("Call me from a string!"); },
f2: function(str1) { this[str1](); }
}
Now you can:
var m = require('m.js');
m.f2('f1');
Or even just:
var m = require('m.js');
m['f1']();
FWIW!
you're looking for global
Note, however, that in modules nothing is ever exposed to this level
1) If methods are in same js file
define all methods as properties of Handler:
var Handler={};
Handler.application_run = function (name) {
console.log(name)
}
Now call it like this
var somefunc = "application_run";
Handler[somefunc]('jerry codes');
Output: jerry codes
2) If you want to keep methods in a different js file
// Handler.js
module.exports={
application_run: function (name) {
console.log(name)
}
}
Use method defined in Handler.js in different.js:
// different.js
var methods = require('./Handler.js') // path to Handler.js
methods['application_run']('jerry codes')
Output: jerry codes
If you want to call a class level function using this then following is the solution and it worked for me
class Hello {
sayHello(name) {
console.log("Hello " + name)
}
callVariableMethod() {
let method_name = 'sayHello'
this[`${method_name}`]("Zeal Nagar!")
}
}
If You need it in module scope, You can use something like this
var module = require('moduleName');
module['functionName'](arguments);
Honestly, looking at all these answers they seem a bit too much work. I was playing around to look for other ways around this. You can use the eval() command to print a variable as text then call it as a function
I.e
let commands = ['add', 'remove', 'test'];
for (i in commands) {
if (commands[i] == command) {
var c = "proxy_"+command;
eval(c)(proxy);
}
}
eval(string)(arg1, arg2);
This example script would execute the function proxy_test(proxy)
You know, the OP's code inspired me to try this:
global.test = function(inVal){
console.log(inVal);
}
global['test']('3 is the value')
But now that I think about it, it's no better than #Ravi' s answer.
I use this for node, see if this approach works for you
var _ = require('lodash');
var fnA1 = require('functions/fnA1');
var fnA2 = require('functions/fnA2');
module.exports = {
run: function(fnName, options, callback) {
'use strict';
var nameSpace = fnName.toString().split('.');
// if function name contains namespace, resolve that first before calling
if (nameSpace.length > 1) {
var resolvedFnName = this;
_.forEach(nameSpace, function(name){
resolvedFnName = resolvedFnName[name];
});
resolvedFnName(options, callback);
} else {
this[fnName](options, callback);
}
},
fnA1: fnA1,
fnA2: fnA2
};
call this like
importVariable.run('fnA1.subfunction', data, function(err, result){
if (err) {return callback(err);}
return callback(null, result);
});
That is not specific to the window object. In JavaScript any property of the object can be accessed this way. For example,
var test = {
prop1 : true
};
console.log(test.prop1); // true
console.log(test["prop1"]); // also true
Read more here : https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects

jqGrid - Changing the Label of a Column

I have all UI related methods in UIManager.js module, i.e. loadGrid, filterGrid, reloadGrid, clearGrid etc. I have a need of changing the Heading of a column in my App. So I wrote a function in UIManager as,
var UIManager = (function() {
"use strict";
var setGridOptions = function (options) {
var args = options;
args.$grid.jqGrid(args.options);
};
return {
setGridOptions:setGridOptions
};
})();
then I called it as,
UIManager.setGridOptions({
$grid: $grid,
options: ["setLabel", "rn", "Sample Heading"]
});
Please note that following variable was initialized before calling the UIManager.setGridOptions.
var $grid = $("#grid"); //Element.
Sadly, the UIManager.setGridOptions doesn't work. I am not sure if there is something wrong with passing the options as array or anything else.
But, if I change the UIManager.setGridOptions to the following then it works, but it looses the purpose of having a function.
var setGridOptions = function (options) {
var args = options;
args.$grid.jqGrid("setLabel", "rn", "Sample Heading");
//$grid.jqGrid(args.options);
};
Can we fix the code in the call, to use our function? Your help will be appreciated.

Losing context with parse.com javascript SDK

So the goal of what I'm doing it to store an array of objects inside an object literal for later reference. I am losing context(if that is the right terminology to use here) in a place that is confusing for me. Here is the code:
HuntObject = {
// Data.hunts gives collection
Data: {},
fetchCollec: function(){
var self = this;
var huntObj = new Parse.Query(huntObject);
huntObj.find({
success: function(results){
var hunts = [];
for(i in results){
hunts.push(i);
}
console.log(self);
//Here self references HuntObject
self.Data = hunts;
},
error: function(e){
console.log(e.message);
}
});
console.log(self);// Here self references HuntObject
console.log(self.Data); // empty
So in both my console.log statements the correct context that I want is referenced and in the last log call to self I can even see in the console that the Data object now has an array of objects in it. But than as soon as I try to reference that array I get an empty Object. I tried assigning the array in different ways like self.Data.array = hunts. I also tried to set up Data as a method like this.
Data: (function(){
return {
array: []
}
}());
I think maybe my understanding of how context changes in different situations is pretty weak so It would be nice to solve my original goal but more important I would like to understand context better and why my implementation is failing in this instance?
This isn't a scope or context issue, you're handling that with your self variable.
My guess is that Parse.Query is asynchronous. And so you'd have to do your console.log within the success function; doing it in the code immediately after the call to Parse.Query calls it too soon (before the query completes).
So:
huntObj.find({
success: function (results) {
var hunts = [];
for (i in results) {
hunts.push(i);
}
console.log(self);
//Here self references HuntObject
self.Data = hunts;
// *********** Move these here
console.log(self); // Here self references HuntObje
console.log(self.Data); // Not empty anymore
},
error: function (e) {
console.log(e.message);
}
});
// Any code here runs after you've *started* the query, but
// before it *completes*

KnockoutJS - update object with internal function

I am having an "this" issue and would appreciate any help
this is my basic code
function xxx(val)
{
this.x = val;
this.change = function() {
var self = this;
$.ajax({
blah: '',
blah: '',
success: function(data) { self.x = 5; },
});
};
}
var newX = new x(1);
newX.change();
console.log(newX.x);
Hopefully that makes sense,
What I am trying to do is update the original object on the jquery ajax response. I do not have access to 'this' so i tried to pass it off to the 'self' variable but the object values does not seem to be updating even though the code is running as expected.
I am sure there is a simple answer, i just dont know it.
Any help is greatly appreciated.
So the way to resolve this is take a look at your function declarations. Each function declaration will give you a new this object. Store the one you are interested in the correct spot. If I'm correct, it looks like you actually want to access the scope of the original xxx function scope. So instead of storing this in the change function, store it above that in the original scope. Something like this:
function xxx(val)
{
var self = this;
this.x = val;
this.change = function() {
var that = this;
$.ajax({
blah: '',
blah: '',
success: function(data) { self.x = 5; },
});
};
}
var newX = new x(1);
newX.change();
console.log(newX.x);
The other issue here is that you are using AJAX to make that call so you either need a Deferred object or you could add a callback to that function that gets triggered at the right time like so:
function xxx(val)
{
var self = this;
this.x = val;
this.change = function(callback) {
var that = this;
$.ajax({
blah: '',
blah: '',
success: function(data) {
self.x = 5;
if (typeof callback === "function"){
callback.call(this);
}
}
});
};
}
var newX = new xxx(1);
newX.change(function(){
console.log(newX.x);
});
In knockout... you'll have to do something like that:
function Xxx(val)
{
var self = this;
this.x = ko.observable(val);
this.change = function() {
// "that" may be different to "self" in some
// cases...
var that = this;
$.ajax({
url: '...',
type: 'get',
success: function(data) {
self.x(5);
},
error: function(a) {
console.log('got an error');
}
});
};
}
var newX = new Xxx(1);
newX.change();
ko.computed(function () {
// This will get called everytime
// newX.x is changed
console.log(newX.x());
});
When you create a variable, that may change, you have to create it as an observable. The observable is in fact a function that you call. When called, it will update its inner value and it will also trigger any changes wherever the observable is "observed"
In no way you should try to do this.x = 5. It will override the actual observable object and thus it will never trigger every observer of a change.
edit
In case you're interested to understand how does computed works. A computed variable is a function that will listen to observables. When the computed is created, it will be called once to check which observables where called from within it. It's a way to "track" dependencies. In this example, you should see at least two console log. one with 1, and then with 5.
In my case, the computed variable is kind of anonymous since it isn't affected anywhere. Also in some case, you may need to observe one variable but use multiple observables. To prevent update on any other used observables. There are some ways to do that. You can either return after you "watched" the observables you needed.
Or you can create a sub function that will be triggered a little after the computed with setTimeout(..., 0);. There are a couple of ways to achieve some really nice tricks.

Code Structure with ExtJS

I'm trying to organize my ExtJS javascript a little better. I've an ExtJS object like this:
Ext.define('QBase.controller.ControlModelConfigurationController', {
extend: 'Ext.app.Controller',
views: [
'ControlModelConfiguration'
],
init: function() {
console.log('Initialized ControlModelConfigurationController');
this.control({
'#testBtn': {
click: this.loadModel
}
});
},
loadModel: function() {
console.log('Load Model....');
var conn = new Ext.data.Connection;
conn.request({
url: 'partsV10.xml',
callback: function(options, success, response)
{
if (success)
{
alert("AHHH");
var dq = Ext.DomQuery;
var xml = response.responseXML;
var nodes = dq.select('part', xml,parent);
Ext.Array.forEach(nodes,handleNode);
}
}
});
},
handleNode: function(items) {
console.log(item.name);
}
});
The posted code above is not working. Ext.Array.forEach(nodes,handleNode) causes trouble. Instead of using an anonymous function like :
...
Ext.Array.forEach(nodes,function(item) {
console.log(item)});
}
...
I'd like to extract the anonymous function as a named external one. Unfortunately I'm unable to figure out the right syntax to establish a code structure as shown above.
Meanwhile, I figured out, that putting
function handleNode(item) {
{console.log(item)}
}
at the very end of the file works. Is it possible to make the handleNode method an object - "member" of the controller?
Thanks in advance
Chris
handleNode is a member of the containing object. When loadModel is called, this contains the right object, but at the time the callback is invoked, it will not point to the one we are interested in. You can save this to the local variable self, and use it instead.
loadModel: function() {
var self = this
console.log('Load Model....');
var conn = new Ext.data.Connection;
conn.request({
url: 'partsV10.xml',
callback: function(options, success, response)
{
if (success)
{
alert("AHHH");
var dq = Ext.DomQuery;
var xml = response.responseXML;
var nodes = dq.select('part', xml,parent);
Ext.Array.forEach(nodes, self.handleNode);
}
}
});
},
The solution posted by vhallac is not entirely correct. It assumes that handleNode doesn't reference the current object through this variable. Maybe just a typo, but additionally it's not really the ExtJS way...
Whenever ExtJS provides a callback parameter, there is nearly always a scope parameter to set the value of this within the callback function.
loadModel: function() {
console.log('Load Model....');
var conn = new Ext.data.Connection;
conn.request({
url: 'partsV10.xml',
callback: function(options, success, response) {
if (success) {
alert("AHHH");
var dq = Ext.DomQuery;
var xml = response.responseXML;
var nodes = dq.select('part', xml, parent);
Ext.Array.forEach(nodes, this.handleNode, this);
}
},
scope: this
});
},
handleNode: function(node) {
// From within here you might want to call some other method.
// Won't work if you leave out the scope parameter of forEach.
this.subroutine();
}
Just like forEach uses a scope parameter, the request method uses a scope config option. This is ExtJS convention for passing around the scope. You can alternatively create an extra local variable and reference the scope from there, but in the context of ExtJS this style will feel awkward, plus (I'm pretty sure) it's a lot more bug-prone.

Categories