I am working on a script and everythink worked fine, until a few days ago. I have an object, created with function(), where I work with several methods.
To access properties inside the object, I use the this keyword and that works fine.
As example:
var SeralCore = SeralCore || function ()
{
this.initSeral();
return this;
};
SeralCore.prototype = {
page = null;
initSeral = function ()
{
alert(this.page);
}
}
Full code: http://pastebin.com/81Zn9276
jsFiddle example: https://jsfiddle.net/g2ahu6ob/10/
When I have an event, where a callback is fired and I have to access the property page, I used the following, because I can't use this anymore:
$('.button').click(function () {
SeralCore.page = 'Some value';
});
This worked well, but suddenly there is an error saying I cannot reach an property (or object, in my case*) used like in the exameple above. The output is undefined.
I decided to investigate what the output would be if I log SeralCore. Surprisingly, it says the following:
As you can see, there is a < at the end of SeralCore, which doesn't belong there.
Is this normal? And is this the cause of not being able to access properties using the "full name" (SeralCore.page)? If so, is there a way to fix it?
Many, many thanks in advance because I can't figure out what I am doing wrong.
Snippet:
var SeralCore = SeralCore || function () {
this.initSeral();
return this;
};
window.onload = function () {
this.SeralCore = new SeralCore();
};
SeralCore.prototype = {
page: 'Page',
initSeral: function ()
{
this.registerPage.start();
},
registerPage: {
start: function ()
{
$('.output').text(typeof SeralCore.page + ' (Should show \'String\' when it can read SeralCore.page)');
}
}
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<span class="output"></span>
Related
When trying to put following Script into a CEWP on a Listview:
; (function ()
{
var fieldJsLinkOverride = {};
fieldJsLinkOverride.Templates = {};
fieldJsLinkOverride.Templates.Fields =
{
'Title': { //Titelfeld
'View': function () {
return ''+ctx.CurrentItem.Title+''
}
}
};
// Register the rendering template
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(fieldJsLinkOverride);
})();
So this changes the Title field into my desired link, this works all fine, but when i try to sort the list, it returns following:
Unable to get property 'ItemID' of undefined or null
Does anyone know this problem or might find a solution for it?
You are using ctx in your code but you have not passed it to your function..
Remember Each of the functions you write for JS Link will be passed a “context” object as a parameter. From this object you can retrieve properties about the current list, current list item and other objects.
Refer below code. Here we are passing ctx to a function. Try this :
{
'Title': { //Titelfeld
'View': function (ctx) {
return ''+ctx.CurrentItem.Title+''
}
}
};
I am trying to fix a function I have here to be able to use it without using a that = this (or self = this as some like to use). It is a scoping issue but I am not sure how to get around it, and I would like to get in the habit of not using a that = this . So the functions are all in a return (angular factory) and I am having trouble referencing another function . Let me show you what I mean :
return {
loadStates: function() {
var that = this;
//chgeck if is loaded module, then change and fire callback
var currentModules = moduleHolder.getModules();
if (currentModules[name]) {
//works here
this.prepState();
} else {
//module cannot be found check for 5 seconds
$log.warn("Requesting " + name + "...");
var timeToCheck = true;
setTimeout(function() {
timeToCheck = false;
}, 5000);
var check = {
init: function() {
check.checkAgain();
},
checkAgain: function() {
if (timeToCheck) {
if (currentModules[name]) {
//but not here
that.prepState();
} else {
//still doesn't exists
setTimeout(check.checkAgain, 200);
}
} else {
//doesn't exist after 5 seconds
$log.error("Requested module (" + name + ") could not be found at this time.");
}
}
};
check.init();
}
},
prepState: function() {
}
}
So in the top if it finds the currentModule[name] I can use a this.prepState() and it works fine. However inside the timing functions I cannot use the this anything because it is inside a different scope so I have temporarily gotten around this by setting a that = this up top, however I would like see if I could not use this method. How does one get around this without using the that= this? Thanks!
It is a scoping issue...
No, it isn't. this and scope have essentially nothing to do with each other. (For now; ES6's arrow functions will change that.) It's an issue of how the functions are called.
If you pass a function reference to something that will call it later, unless the thing you're passing it to has a way you can use to tell it what to use for this when calling it, your function will get called with this not referring to what you want it to refer to.
You can get a new function reference that will call your original function with the correct this by using Function#bind:
var usesCorrectThis = originalFunction.bind(valueForThis);
So for example, suppose I have:
var check = {
name: "Fred",
sayHello: function() {
console.log("Hi, I'm " + this.name);
}
};
If I do:
check.sayHello();
All is good: Calling the function as part of an expression retrieving it from a property tells the JavaScript engine to use the object as this during the call.
However, if I do:
setTimeout(check.sayHello, 0);
...that doesn't work right, because when setTimeout calls the function, it doesn't use the right value for this.
So I can use Function#bind to address that:
setTimeout(check.sayHello.bind(check), 0);
More (on my blog):
Mythical methods
You must remember this
there are different ways you can do that.
One way is to use bind function.you can use
var checkInitBindFn = check.init.bind(this);
checkInitBindFn();
Secondly you can use call and apply also.
check.init.call(this);
check.init.apply(this);
Like this you can use this instead of that.
Check the complete api doc online...
It's not a scoping issue. If you want to avoid self = this you can always reference functions by objects. Makes cleaner code and since factories in angular are singletons you're not wasting memory.
angular.module('myApp').factory('myFactory', function ($timeout) {
var myFactory = {
loadState: function () {
$timeout(function () {
myFactory.check();
}, 500);
},
check: function () {
},
};
return myFactory;
});
I make a simple quiz game. Here is some relevan methods that i have inside one object.
But doesn't work. I always get an error within 'rightAnswerGot' function. Console drops
"uncaught typeerror undefined is not a function for object methods" for this.addVariantsHtml(this.updateCharacter());
BasicGame.Game.prototype = {
actionOnClick: function (button) {
var log;
if(button.value==this.char_bubble.text) {
setTimeout(this.rightAnswerGot,1000);
} else {
// wrong
swoshsound.play();
}
console.log(log);
},
rightAnswerGot: function (){
this.addVariantsHtml(this.updateCharacter());
},
addVariantsHtml: function(id) {
this.answer = this.getAnswersVariants(id);
for (var i = 0; i < 6; i++) {
this.button[i].value = this.answer[i]['trans'];
this.button[i].char_id = this.answer[i]['id'];
this.ans_text[i].setText(this.answer[i]['trans']);
}
},
updateCharacter: function() {
var i = this.getRandomCharacter();
console.log("updateCharacter: "+i + " " +this.chars[i]);
this.char_bubble.setText(this.chars[i].getPath());
return i;
}
}
The aim is to froze the game for a second, when user choose the right answer, and than go to next question. Any ideas why does it happens?
Thanks
Looks like a classic JavaScript scope issue to me. However as you've tagged this question as using Phaser, I would suggest you use a Phaser Timer event to avoid scope problems. Specifically:
setTimeout(this.rightAnswerGot,1000);
replace it with:
this.game.time.events.add(Phaser.Timer.SECOND, this.rightAnswerGot, this);
Which will create a single 1 second timer that fires only once, calling your function at the end of it. You can use 1000 instead of Phaser.Timer.SECOND of course.
I would image that whats happening is that its trying to call the this.addVariantsHtml method, before its calling this.updateCharacter and getting the ID.
So your probably expecting that when it runs, for it to be something like:
this.addVariantsHtml(1);
But its actually trying to run
this.addVariantsHtml(this.updateCharacter());
So just do this:
var id = this.updateCharacter();
this.addVariantsHtml(id);
Either that or you need to look into method chaining/piping, which is just complicated and doesnt need to be used for this situation, but is interesting :)
Ok I found something that made it work!!
Here is a solution:
actionOnClick: function (button) {
var log;
if(button.value==this.char_bubble.text) {
var context=this;
setTimeout(function() {
context.addVariantsHtml(context.updateCharacter());
},1000);
} else {
// wrong
swoshsound.play();
}
console.log(log);
},
I'm a bit stuck on a problem which I can't solve, I performed investigation on internet and on this site, but I can't find the answer to my question.
So basically I have a javascript file, which I cannot modify, so I have another javascript file which should catch the method when it is called and override it.
Normally I know how it works and I already done the function overriding, but I don't know how to solve this issue.
I have a very big script, but I will show just a small piece of it:
Microsoft.Office.Server.Ajax.NavResizer.prototype = {
$6: null,
$7: null,
......
$20:function ($p0) {
if (this.$1E) {
$p0.preventDefault();
}
},
$21: function ($p0) {
var $0 = $p0.target;
this.$1F = ($0 === this.$A);
if (this.$1F || $0 === this.$B) {
this.$1E = $0;
this.$18 = $p0.clientX;
this.$19 = $p0.clientY;
Sys.UI.DomEvent.removeHandler(this.$1E, 'mousedown', this.$12);
var $1 = document.body; Sys.UI.DomEvent.addHandler($1, 'mouseup', this.$13);
Sys.UI.DomEvent.addHandler($1, 'mousemove', this.$14);
$1.style.cursor = (this.$1F) ? 'e-resize' : 'n-resize';
this.$1A = this.get_$42();
this.$1B = this.get_$43();
$1.focus();
Sys.UI.DomEvent.addHandler($1, 'selectstart', this.$15);
$p0.preventDefault();
}
},
$22: function ($p0) {
this.$34($p0);
var $0 = document.body;
Sys.UI.DomEvent.removeHandler($0, 'mouseup', this.$13);
Sys.UI.DomEvent.removeHandler($0, 'mousemove', this.$14);
Sys.UI.DomEvent.addHandler($0, 'selectstart', this.$15);
$0.style.cursor = 'default';
Sys.UI.DomEvent.addHandler(this.$1E, 'mousedown', this.$12);
this.$1E = null;
},
$23: function ($p0) {
this.$34($p0);
},
$24: function ($p0) {
this.$26();
},
....
Basically this is the part of the script: so lets say I want to override function: $22: function ($p0) in the script in another javascript file, how do i do that?
I would appreciate any help.
A small update, some good examples were provided but they are not working.
The environment where i run this sript is SharePoint, normally when I did override I used this method:
var oldFixRibbonAndWorkspaceDimensions = window.FixRibbonAndWorkspaceDimensions;
window.FixRibbonAndWorkspaceDimensions = function () {
this.MyFixRibbonAndWorkspaceDimensions();
};
function MyFixRibbonAndWorkspaceDimensions(){...}
And it didn't matter when i load the script as this function was only called when the default function was called not before not after. Just in the same time. But with the example which were provided here, the function is trying to execute on the document.ready()
You want to permanently override it? Just do this:
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function($p0) {
// your code.
};
As long as your script is executed after the original is defined, you're good.
Old post.. but this works for me:
ExecuteOrDelayUntilScriptLoaded(overrideNavResizer, "NavResizer.js");
function overrideNavResizer(){
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function($p0) {
// your code.
};
}
In your new script:
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function () {//your function code}
Assuming you have access to the prototype object (it's in global scope) and your scripts runs after it, that is easy:
var proto = Microsoft.Office.Server.Ajax.NavResizer.prototype,
oldMethod = proto.$22;
proto.$22 = function newMethod(args, …){
…
};
I need to know what I am doing wrong because I cannot call the internal functions show or hide?
(function()
{
var Fresh = {
notify:function()
{
var timeout = 20000;
$("#notify-container div").get(0).id.substr(7,1) == "1" && (show(),setTimeout(hide(),timeout));
var show = function ()
{
$("body").animate({marginTop: "2.5em"}, "fast", "linear");
$("#notify-container div:eq(0)").fadeIn("slow");
},
hide = function()
{
$("#notify-container div").hide();
}
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
thanks, Richard
UPDATE
If you wanted to be able to do something like: Fresh.notify.showMessage(), all you need to do is assign a property to the function notify:
var Fresh = {notify:function(){return 'notify called';}};
Fresh.notify.showMessage = function () { return this() + ' and showMessage, too!';};
Fresh.notify();//notify called
Fresh.notify.showMessage();//notify called and showMessage, too!
This will point to the function object here, and can be called as such (this() === Fresh.notify();). That's all there is too it.
There's a number of issues with this code. First of all: it's great that you're trying to use closures. But you're not using them to the fullest, if you don't mind my saying. For example: the notify method is packed with function declarations and jQuery selectors. This means that each time the method is invoked, new function objects will be created and the selectors will cause the dom to be searched time and time again. It's better to just keep the functions and the dom elements referenced in the closure scope:
(function()
{
var body = $("body");
var notifyDiv = $("#notify-container div")[0];
var notifyDivEq0 = $("#notify-container div:eq(0)");
var show = function ()
{
body.animate({marginTop: "2.5em"}, "fast", "linear");
notifyDivEq0.fadeIn("slow");
};
var hide = function()
{//notifyDiv is not a jQ object, just pass it to jQ again:
$(notifyDiv).hide();
};
var timeout = 20000;
var Fresh = {
notify:function()
{
//this doesn't really make sense to me...
//notifyDiv.id.substr(7,1) == "1" && (show(),setTimeout(hide,timeout));
//I think this is what you want:
if (notifyDiv.id.charAt(6) === '1')
{
show();
setTimeout(hide,timeout);//pass function reference
//setTimeout(hide(),timeout); calls return value of hide, which is undefined here
}
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
It's hard to make suggestions in this case, though because, on its own, this code doesn't really make much sense. I'd suggest you set up a fiddle so we can see the code at work (or see the code fail :P)
First, you're trying to use show value when it's not defined yet (though show variable does exist in that scope):
function test() {
show(); // TypeError: show is not a function
var show = function() { console.log(42); };
}
It's easily fixable with moving var show line above the point where it'll be called:
function test() {
var show = function() { console.log(42); };
show();
}
test(); // 42
... or if you define functions in more 'traditional' way (with function show() { ... } notation).
function test() {
show();
function show() { console.log(42); };
}
test(); // 42
Second, you should use this instead:
... && (show(), setTimeout(hide, timeout) );
... as it's the function name, and not the function result, that should be passed to setTimeout as the first argument.
You have to define show and hide before, also change the hide() as they said.
The result will be something like this:
(function()
{
var Fresh = {
notify:function()
{
var show = function()
{
$("body").animate({marginTop: "2.5em"}, "fast", "linear");
$("#notify-container div:eq(0)").fadeIn("slow");
},
hide = function()
{
$("#notify-container div").hide();
},
timeout = 20000;
$("#notify-container div").get(0).id.substr(7,1) == "1" && ( show(), setTimeout(hide,timeout) );
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
I think order of calling show , hide is the matter . I have modified your code . It works fine . Please visit the link
http://jsfiddle.net/dzZe3/1/
the
(show(),setTimeout(hide(),timeout));
needs to at least be
(show(),setTimeout(function() {hide()},timeout));
or
(show(),setTimeout(hide,timeout));