Why I always get 'false' value in my case? - javascript

I have a function in testFun.js
var testFunc=function{
var hasCar=false;
return{
checkCar: function(){
for(var i=0; i<5; i++){
MyCar.check(hasCar); //defined in following MyCar.js
}
}
}
}();
Another function in MyCar.js
var MyCar=function(){
var createCar=function(){
//Create a car
//var car = new Car();
}
return{
check: function(hasCar){
console.log(hasCar); //PROBLEM HERE: fierBug console output is "false" always even CHECK_BUTTON has been clicked, why?
var handler=function(){
if(!hasCar)
createCar();
hasCar=true;
}
//CHECK_BUTTON is a button on UI
CHECK_BUTTON.click(handler);
}
}
}();
As you see in MyCar module pattern, when CHECK_BUTTON is clicked, I will call createCar() function, and change hasCar value from false to true.
The hasCar is defined in testFunc module pattern, and pass to MyCar.check(hascar).
I have a fireBug console output inside MyCar.check() function, I expect that when mouse clicked the CHECK_BUTTON, the console output will be true, but I always get false, why? I use hasCar to check is the CHECK_BUTTON has been clicked once or not, but if it always hold false value, I cannot know it. How to get rid of this?

Primitive values are passed by value and not by reference.
Thus assigning true to hasCar inside the click event handler (in MyCar.check) does not change the value of hasCar defined in testFunc.
You could use an object instead:
var testFunc= (function(){
var hasCar = {val: false};
// ...
}());
var MyCar=(function(){
//...
return{
check: function(hasCar){
console.log(hasCar.val);
var handler=function(){
if(!hasCar.val)
createCar();
hasCar.val=true;
}
CHECK_BUTTON.click(handler);
}
}
}());
Or define the hasCar variable in a scope accessible to both functions.
Update:
You will still get false in the console because hasCar.val is only set to true after you clicked the button and you never call console.log when you click the button.
Using a loop here does not tell you anything. More appropriate for testing would be, given your setup:
var hasCar = {val: false};
MyCar.check(hasCar); // will output false
// now click the button
MyCar.check(hasCar); // will output true
Have a look at this DEMO.
Further notes:
For better compatibility, surround your self invoking functions with parenthesis.
You are adding a new click handler every time MyCar.ceck is called. I don't think this is desired.
The structure of your application is quite confusing (at least for me ;)).

Related

How to change value in a class with a prototype method?

In the code below I'm trying to change the value of the property isTired to true using the prototype method .rest. When I call it with either mommy.rest() or mommy.rest.bind(mommy) it turns isTired to true. If I call mommy.isTired immediately after it results to true.
However, if I delete the call, it turns the value false. I was looking through other stack overflow responses and I believe this can be solved by using bind. I've read MDM but just can't seem to find a way to retain the value.
var SuperHero = function() {
this.isTired = false;
}
SuperHero.prototype.rest = function() {
this.isTired = true;
console.log(this.isTired)
}
var SuperHuman = function(greeting) {
SuperHero.call(this)
this.greeting = greeting;
this.speed = 'normal';
}
SuperHuman.prototype = Object.create(SuperHero.prototype)
SuperHuman.prototype.constructor = SuperHuman
var mommy = new SuperHuman('hola')
var mom = mommy.rest.bind(mommy)
mom() // -> outputs true
mommy.isTired //-> outputs true if I keep mom(), but if i delete it it turns false
Your code is mostly right but you're getting mixed up at the end.
Everything after the first line is wrong.
var mommy = new SuperHuman('hola')
var mom = mommy.rest.bind(mommy)
// mom() // -> outputs true
mommy.isTired //-> outputs true if I keep mom(), but if i delete it it turns false
Just do this:
var mommy = new SuperHuman('hola')
mommy.rest();
// mommy.isTired is now true
As long as your reference to mommy exists, isTired will remain true until/unless another function changes it.
Using bind does nothing for you in this situation. All bind does is execute a function in the context of a different this. That doesn't apply in this case.
what you are trying to do with
var mom = mommy.rest.bind(mommy)
is that you are setting (bind) a new context this to the function rest(). So in rest() the type of this === Superhuman which the value is mommy object.
When you call mom() it invokes the rest() then sets this.isTired = true; else this.isTired = false;
If you want to call rest(), you would mommy.rest();. Pretty simple

Not able to access a variable

The variable i am using becomes undefined after a certain point. Can someone help me in understanding what is happening.
The below code is a protractor code.
this.searchBy = element(by.model('searchCompanyComponent.searchByValue'));
this.clickTheProvidedValueInSearchByDropdown = function (selectedItem) {
var x = this.searchBy;
this.searchBy.all(by.tagName('option')).filter(function (elem, index) {
return elem.getText().then(function (text) {
return text.toUpperCase().replace(/ |-/g, '') === selectedItem.toUpperCase().replace(/ |-/g, '');
});
}).getText().then(function (text) {
console.info(x); // 1
console.log(this.searchBy); // 2
});
};
console.log(this.searchBy); //3
The console log at 1 and 3 shows the locator object, but console log at 2 shows as undefined.
What is the reason behind this unexpected behavior?
In JavaScript, this can mean a lot of different things depending on the context in which you are referencing it.
When you are saying console.log(this.searchBy); // 2 you are in the context of the anonymous function you passed to getText, which has no searchBy property. You will either need to bind this function to the context of your page object or use the stored reference to searchBy in x
It may be helpful to review this mdn article

In a custom widget, inside a validation handler of addMethod(), I have a wrong context (this)

I'm creating a custom combobox which uses jQuery validator.
At first they all are gray except the first (it means Country). When I choose 'Slovenská republika' the second combobox is enabled.
They all are instances of a a custom autocomplete combobox widget.
To enable the validation I use this code (which is called within _create: function(){..})
There you can find $.validator.addClassRules(); and $.validator.addMethod(). I also added the appropriate class so it really does something.
_registerCustomValidator: function(){
var uniqueName = this._getUniqueInstanceNameFromThisID(this.id);
var that = this;
console.log(this.id);//this prints 5 unique ids when the page is being loaded
$.validator.addMethod(uniqueName, function(value,element){
if(!that.options.allowOtherValue){
return that.valid;
}
console.log(that.id);//this always prints the ID of the last combobox StreetName
return true;
}, "Error message.");
var o = JSON.parse('{"'+uniqueName+'":"true"}');
$.validator.addClassRules("select-validator", o);
}
//this.id is my own property that I set in _create
Problem: When I change the value of any instance of combobox, it always prints the ID of the last instance StreetName, but it should belong to the one that has been changed.
I thought it might be because of registering $.validator.addMethod("someName",handler) using such a fixed string, so now I pass a uniqueName, but the problem remains.
Therefore the validation of all instances is based on the property allowOtherValue of the last instance.
I don't understand why it behaves so. Does anyone see what might be the problem?
EDIT:
see my comments in the following code
_registerCustomValidator is a custom function within a widget factory.
//somewhere a global var
var InstanceRegistry = [undefined];
//inside a widget factory
_registerCustomValidator: function(){
var i=0;
while(InstanceRegistry[i] !== undefined) ++i;
InstanceRegistry[i] = this.id;
InstanceRegistry[i+1] = undefined;
var ID = i; //here ID,i,InstanceRegistry are correct
$.validator.addMethod(uniqueName, function(value,element){
//here InstanceRegistry contains different values at different positions, so its correct
console.log("ID=="+ID);//ID is always 5 like keeping only the last assiged value.
var that = InstanceRegistry[ID];
if(!that.options.allowOtherValue){
return that.valid;
}
return true;
}, "Error message");
var o = JSON.parse('{"'+uniqueName+'":"true"}');
$.validator.addClassRules("select-validator", o);
}
It looks like a sneaky combination of closure logic and reference logic. The callback in $.validator.addMethod is enclosing a reference to this which will equal the last value of this when $.validator.addMethod. (Or something like that?)
Glancing at your code, it's not clear to me what this is in this context. So I can't really offer a concrete solution. But one solution might be to create some kind of global registry for your thises. Then you could do something along the lines of:
_registerCustomValidator: function(){
var uniqueName = this._getUniqueInstanceNameFromThisID(this.id);
$.validator.addMethod(uniqueName, function(value,element) {
var instance = InstanceRegistry[uniqueName];
if(! instance.options.allowOtherValue){
return instance.valid;
}
return true;
}, "Error message.");
var o = JSON.parse('{"'+uniqueName+'":"true"}');
$.validator.addClassRules("select-validator", o);
}
The registry could be keyed to uniqueName or id, just so long as it is a value getting enclosed in your callback.

TypeError when using Jquery and Object property function

I'm getting an error when using jquery and I would like to know its cause:
here is part of my code
function Wbook(name){
this.name = name;
}
Wbook.prototype.GetHTML = function() {
Object.defineProperty(this, "GetHTML", {enumerable : false,
configurable : true});
var html ='<h1>TEST1</h1>';
return html;
};
var rs = {};
rs.WB = new Wbook('test1');
var foo = rs.WB.GetHTML();
$(foo).appendTo('div#id1'); // This works
$(rs.WB.GetHTML()).appendTo('div#id1');
// This doesn't work >> TypeError: rs.WB.GetHTML is not a function
I can also getting to work if I comment the Object.defineProperty section, so I'm suspecting this might have to do with the enumerability, but I'm not sure of it
//Edit: While creating Jfiddle, I notice rs.WB.GetHTML() is always failing the second time it runs :-/. (It works fine if I comment the Object.defineProperty section)
The first time you call .GetHTML() it's returning some HTML, but in the process the Object.defineProperty call is overwriting the .GetHTML method with a new property that has no value.
It's therefore unsurprising that on the second invocation you get an error because the value of .GetHTML by then is undefined.
If the intent of your code is to ensure that GetHTML is not enumerable, use the following code which directly adds the method to Wbook.prototype and (automatically) sets it non-enumerable:
Object.defineProperty(Wbook.prototype, 'GetHTML', {
value: function() {
...
}
});

Retrieving the value of a variable through a closure

I have the following module pattern in the javascript for a webpage:
var swf_debugger = swf_debugger || {};
(function($, swf_debugger) {
swf_debugger.pageSetup = (function() {
var
swfType = null,
formData = {},
// ... unimportant code continues ...
initChangeEvents = function() {
$.each(formElements, function(index, $el) {
if ($el.hasClass("swfToLoad")) {
// THIS EVENT IS WHERE I MAKE THE ASSIGNMENT TO 'swfType'
$el.change(function() {
swfType = $("option:selected", this).val();
console.log("swfToLoad has triggered");
console.log(swfType);
});
return;
}
// NO ISSUES HERE WITH THESE EVENTS...
switch($el.prop("tagName")) {
case "SELECT":
$el.change(function() {
formData[$el.attr('id')] = $("option:selected", this).val();
});
break;
case "INPUT":
switch ($el.attr('type')) {
case "text" :
$el.change(function() {
formData[$el.attr('id')] = $(this).val();
});
break;
case "checkbox" :
$el.change(function() {
formData[$el.attr('id')] = $(this).prop("checked");
});
break;
default:
}
break;
default:
}
});
},
init = function() {
$(function() {
addFormComponents();
populateDropdowns();
initCachedData();
initChangeEvents();
});
};
init();
return {
swfType: swfType,
formData: formData
};
}());
}($, swf_debugger));
Essentially I am attaching an event to a series of jquery selected elements, with the callback simply storing the contents of a particular form element (specifically select, text, and checkbox elements) in a variable or an object.
I know my events are attaching properly because when I add console.log statements to them I can see them firing. Also, whenever I call swf_debugger.pageSetup.formData in the console I see valid contents of the object that each of those events are populating, so those events are doing what they're supposed to.
My troubles are happening whenever I try to access swf_debugger.pageSetup.swfType it always returns null and I am not understanding why. I know that the particular event feeding this value, is firing and I know that at least within the function scope of the callback, swfType is valid because of what is returned in my console.log statements. However, whenever I try to access the contents of swfType through the closure, (i.e. typing swf_debugger.pageSetup.swfType in the console), It always returns null.
I am guessing that I am running into the difference between an objects reference being passed and a variables value being passed, but I am not sure. Can someone please help me along here and explain why swfType is always returning null through the closure.
why is swfType always returning null
Because that's the value which you assigned to the property (gotten from the swfType variable which had that value at the time of the assignment). A property is not a reference to the variable assigned to it - you can only assign a value.
What you can do:
make the object property a getter method which returns the value of the local swfType variable whenever it is called
don't use a variable but assign to the property of the swf_debugger.pageSetup object each time

Categories