Here is a function that is in one of my objects:
updatePorts: function(nodeKey, portOptions, portArrays) {
var showing_ports = false;
$('#ports li').removeClass('active').hide();
$('#ports .tab-pane').removeClass('active in');
$.each(portOptions, function(side, options) {
if (options.editable) {
$('#ports [href="#'+side+'"]').closest('li').show();
if (!showing_ports) {
$('#ports [href="#'+side+'"]').closest('li').addClass('active');
$('#ports #'+side).addClass('active in');
}
$.each(portArrays[side], function(i,port) {
//do stuff
}
showing_ports = true;
}
})
}
My problem is that outside of the $.each loop I can access the portArrays variable that is passed as an argument into the function. However, I cannot access that same variable inside of the $.each loop.
Am I doing something wrong? How can I gain access to that variable inside the loop?
UPDATE: Added code where portArrays is actually being accessed
portArrays is defined where you're using it, but you're using the wrong index. The side variable is an index into portOptions, not portArrays.
What index should it have? If these two arrays run in parallel with the same index values, that's generally a bad idea - it's better to use a single array of objects - and at least needs to be documented in your code.
BTW, what is the exact error message in the JS console? If my guess isn't right, the error message would give a clue.
I had the problem described in the subject, however it seems the asker had a problem elsewhere in his code. My code is similar to the below and I could not access what I wanted from this. The first log would work, but the log inside the each loop was undefined. I realise now that this is reassigned when using jquery each - http://api.jquery.com/each/
List.prototype.updateList = function(search) {
console.log(this.id);
$.each(this.data, function(item, tags) {
console.log(this.id); //undefined
};
}
I've changed to using for .. in to iterate my this.data object and it's working. Hope this may help someone.
List.prototype.updateList = function(search) {
console.log(this.id);
for(var key in this.data){
console.log(this.id); //hooray
}
}
Related
I'm new to both protractor and javascript. I ran into a scoping issue which I can't figure out. In the code segment below, the first array access statement works but the second doesn't. What gives?
for(var i=0;i<=1;i++){
console.log(msgs[i]);
element.all(by.className("form-group")).get(i).element(by.className("alert alert-danger")).getText().then(function(txt){
console.log(msgs[i]);
});
}
You just need to change
... .getText().then(function(txt){ ... });
to
... .getText().then((txt) => { ... });
It's called fat arrow function and it does not have it's own this so you can access your array.
So, I have a lot of places with code, when I push some elements to array:
arr.push(...)
But the problem is, that I would like to run custom code after each push. Basically the question is not only about this example. What I want to do is something like this:
func1.func2(...);
After this I want to run another function which will get all things, which func2 did and for example log it. But these functions in code are a lot and it is not desirable to write something like this every time:
if (func1.func2(...)) {
log_results();
}
Instead, for every func1.func2() I want automatically run another separate function, which will get results and log it.
The only way to really accomplish this is to wrap it in a function that does the extra work you want.
function pushAndLog(item) {
arr.push(item);
// Additional Code here
logResults();
}
This is an interesting question. There are plenty of libraries like Lodash that do similar things to functions. Like methods that return copies of functions with arguments partially applied: _.curry. I tested it and it works on Array.prototype.push.
Doing some research I found this post with this answer: JavaScript: clone a function and decided to try to do what you wanted without making the clone method.
Here is what I came up with. Replace the console.log with a call to any function you like or any other code you wish.
Array.prototype.push = (function() {
var old = Array.prototype.push;
var push = function () {
console.log('my new push where I can do what I want, like log some stuff');
return old.apply(this, arguments)
};
return push;
})();
var foo = [];
foo.push(1,2,3);
console.log(foo);
You could add another prototype to Array that uses push inside and then whatever else you want to execute.
let testArr = [];
Array.prototype.pushPlusStuff = function(val) {
this.push(val);
console.log("executing other stuff here");
};
testArr.pushPlusStuff("test");
console.log(testArr);
This will make the .pushPlusStuff method available to all Arrays
Actually gforce301 code helped me. I was dealing with Google dataLayer and the task was to log all push data (except some). This code snippet helped me:
var dataLayer_copy = dataLayer.push;
dataLayer.push = function() {
dataLayer_copy.apply(this, arguments);
console.log(JSON.stringify(arguments));
$.post('/log', {data: arguments}, function() {
}, 'json');
};
I want to be able to put the code in one place and call it from several different events.
Currently I have a selector and an event:
$("input[type='checkbox']").on('click', function () {
// code works here //
});
I use the same code elsewhere in the file, however using a different selector.
$(".product_table").on('change', '.edit_quantity', function () {
// code works here //
});
I have tried following the advice given elsewhere on StackOverflow, to simply give my function a name and then call the named function but that is not working for me. The code simply does not run.
$(".product_table").on('change', '.edit_quantity', function () {
calculateTotals() {
// code does not work //
}
});
So, I tried putting the code into it's own function separate from the event and call it inside the event, and that is not working for me as well.
calculateTotals() {
// code does not work //
}
So what am I doing wrong ?
You could pass your function as a variable.
You want to add listeners for events after the DOM has loaded, JQuery helps with $(document).ready(fn); (ref).
To fix your code:
$(document).ready(function() {
$("input[type='checkbox']").on('click', calculateTotalsEvent)
$(".product_table").on('change', '.edit_quantity', calculateTotalsEvent)
});
function calculateTotalsEvent(evt) {
//do something
alert('fired');
}
Update:
Vince asked:
This worked for me - thank you, however one question: you say, "pass your function as a variable" ... I don't see where you are doing this. Can you explain ? tks. – Vince
Response:
In JavaScript you can assign functions to variables.
You probably do this all the time when doing:
function hello() {
//
}
You define window.hello.
You are adding to Global Namespace.
JavaScript window object
This generally leads to ambiguous JavaScript architecture/spaghetti code.
I organise with a Namespace Structure.
A small example of this would be:
app.js
var app = {
controllers: {}
};
You are defining window.app (just a json object) with a key of controllers with a value of an object.
something-ctlr.js
app.controllers.somethingCtlr.eventName = function(evt) {
//evt.preventDefault?
//check origin of evt? switch? throw if no evt? test using instanceof?
alert('hi');
}
You are defining a new key on the previously defined app.controllers.somethingCtlrcalled eventName.
You can invoke the function with ();.
app.controllers.somethingCtlr.eventName();
This will go to the key in the object, and then invoke it.
You can pass the function as a variable like so.
anotherFunction(app.controllers.somethingCtlr.eventName);
You can then invoke it in the function like so
function anotherFunction(someFn) { someFn();}
The javascript files would be structured like so:
+-html
+-stylesheets
+-javascript-+
+-app-+
+-app.js
+-controllers-+
+-something-ctlr.js
Invoke via chrome developer tools with:
app.controllers.somethingCtlr.eventName();
You can pass it as a variable like so:
$(document).ready(function() {
$('button').click(app.controllers.somethingCtlr.eventName);
});
JQuery (ref).
I hope this helps,
Rhys
It looks like you were on the right track but had some incorrect syntax. No need for { } when calling a function. This code should behave properly once you add code inside of the calculateTotals function.
$(".product_table").on('change', '.edit_quantity', function () {
calculateTotals();
});
$("input[type='checkbox']").on('click',function() {
calculateTotals();
});
function calculateTotals() {
//your code...
}
You could just condense it all into a single function. The onchange event works for both the check box and the text input (no need for a click handler). And jQuery allows you to add multiple selectors.
$('input[type=checkbox], .product_table .edit_quantity').on('change', function() {
console.log('do some calculation...');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="product_table">
<input type="checkbox">
<input class="edit_quantity">
</div>
Here are two samples of code. The first one does not work and the second one does, though I'm completely at a loss as to why. Can someone explain this?
[I'm writing a simple game using a bit of jQuery to be played in a webkit browser (packaged with Titanium later).]
In the first example, Firebug tells me that "this.checkCloud" is not a function.
function Cloud(){
this.checkCloud = function(){
alert('test');
}
$("#"+this.cloudName).click(function(){
this.checkCloud();
});
}
...but then this works:
function Cloud(){
this.checkCloud = function(){
alert('test');
}
var _this = this;
$("#"+this.cloudName).click(function(){
_this.checkCloud();
});
}
This one works perfect.
Why does the first one not work? Is it because "this.checkCloud" is inside of the anonymous function?
in this example:
$("#"+this.cloudName).click(function(){
this.checkCloud();
});
this referrers to the element selected(jquery object).
what you can do is use private functions
var checkCloud = function(){
alert('test');
}
this way you can simply call it inside your anonymous function
$("#"+this.cloudName).click(function(){
checkCloud();
});
That is because the meaning of this can potentially change each time you create a new scope via a function. The meaning of this depends on how the function is invoked (and the rules can be insanely complicated). As you discovered, the easy solution is to create a second variable to which you save this in the scope where this has the expected/desired value, and then reuse the variable rather than this to refer to the same object in new function scopes where this could be different.
Try this:
function Cloud(){
this.checkCloud = function(){
alert('test');
}
var func = this.checkCloud;
$("#" + this.cloudName).click(function(){
func();
});
}
When you assign an even listener to an element, jQuery makes sure that this will refer to the element. But when you create the _this variable, you're creating a closure that jQuery couldn't mess with, even if it wanted to.
I got following code:
function test () {
this.testFunction = function () {
//code to alert or return the string "testFunction"
}
}
var testVar = new test();
testVar.testFunction();
Is there a way to find out the name of the property, which the unnamed function is assigned to? Whatever I tried yet in conjunction with "caller" and "callee" methods didn't yield any success.
Edit:
The reason why I'd like to retrieve the property name is to use it for debugging messages, where I don't have to manually pass the property name to the logger. Performance would be not an issue since this is just for the developing process.
Actually the suggestion to name the function is a good idea ... I think. Does this have any obvious/well-known side effects, beside having to type in the function name twice? :-P
Additionally this brought me to the idea to add a comment at the start of a function which looks something like
/* $$NAME$$="testFunction" */
and which could also be parsed - but JavaScript comments seem to be trimmed in FireFox (unlike IE), and I rather prefer FF for developing. Would there be a way to also display/use JS comments in FF when using the "caller"/"callee" property?
You can cycle through everything that's available in the instance of the object, e.g.
function test() {
this.testFunction = function () {
for (var i in this) {
if (this[i] === arguments.callee) {
alert(i); // alerts 'testFunction'
}
}
}
}
var x = new test();
x.testFunction();
If your intent is to call the function recursively, you can simply name it
this.testFunction = function inner() {
inner();
}