I'm trying to make a state machine but it's not working out. I've got this code so far:
function makeStateMachine() {
this.stateConstructors = new Object();
this.currState = {
update : function(e) {
// Nothing to do here
},
exit : function() {
// Nothing to declare
}
};
this.nextState = null;
var that = this;
this.update = new function(e) {
that.currState.update(e);
that.changeState();
};
this.setNextState = new function(targetState) {
that.nextState = targetState;
};
this.addState = new function(constructor, stateName) {
that.stateConstructors[stateName] = constructor;
};
this.changeState = new function() {
if (that.nextState != null) {
that.currState.exit();
that.currState = new that.stateConstructors[that.nextState]();
that.nextState = null;
}
};
}
When I try to run it firebug displays this error: "TypeError: that.changeState is not a function" at the line in the update function. When I uncomment the changeState() line it starts whining about the EaselJS library being incorrect (which I know is correct, because it works for other projects of mine). Can somebody help me out here? It probably something very simple (just like always) but I just can't spot the error. I can post the rest of the code if you guys like but I don't think it's relevant.
Thanks in advance!
You should be putting those functions in the prototype. You also should not be using = new function(...; just use = function(.... Finally, you don't need that. Try this code:
function makeStateMachine() {
this.stateConstructors = {};
this.currState = {
update : function(e) {
// Nothing to do here
},
exit : function() {
// Nothing to declare
}
};
this.nextState = null;
}
makeStateMachine.prototype.update = function(e) {
this.currState.update(e);
this.changeState();
};
makeStateMachine.prototype.setNextState = function(targetState) {
this.nextState = targetState;
};
makeStateMachine.prototype.addState = function(constructor, stateName) {
this.stateConstructors[stateName] = constructor;
};
makeStateMachine.prototype.changeState = function() {
if (this.nextState != null) {
this.currState.exit();
this.currState = new this.stateConstructors[this.nextState]();
this.nextState = null;
}
};
Related
I am troubleshooting a slider problem at the moment, however, I don't know javascript that well, I have isolated the .js file that is responsible for the slider functioning, there is a destroy function that I would like to fire off, the code looks like this
(function ($) {
$.pixelentity = $.pixelentity || {version: '1.0.0'};
$.pixelentity.peBackgroundSlider = {
conf: {
api: false,
wait: false
},
paused: false
};
function PeBackgroundSlider(target, conf) {
...
function destroy() {
prevColor = currentColor = currentBW = jwindow = jthis = undefined;
target.data("peBackgroundSlider", null);
target = undefined;
}
}
How would I fire off the destroy function in this scenario?
You can't as it is right now.
To call it you must "export" it as follows:
function PeBackgroundSlider(target, conf) {
...
function destroy() {
prevColor = currentColor = currentBW = jwindow = jthis = undefined;
target.data("peBackgroundSlider", null);
target = undefined;
}
return { "destroy": destroy };
}
From the caller:
var ret = PeBackgroundSlider();
Now you can do:
ret.destroy();
Or, more concise:
return destroy;
And:
innerDestroy = PeBackgroundSlider();
And finally:
innerDestroy();
Problem:
I have a piece of code that throws an error: this.isEmpty is not a function,
and I cannot figure out why. Following is the fragment (jsfiddle):
function addAlbumGrid(){
const MainGrid = new AlbumGrid ()
return MainGrid
}
function AlbumGrid() {
MainGrid.call(this)
}
var parentPrototype = Object.create(AlbumGrid.prototype)
parentPrototype.constructor = MainGrid
MainGrid.prototype = parentPrototype
AlbumGrid.prototype.addPhotoBox = function () {
MainGrid.prototype.add.call(this)
}
function MainGrid(){
}
MainGrid.prototype = {
isEmpty: function() {
{
return false
}
},
add:function() {
if(!this.isEmpty())
{
return false
}
}
}
var AlbumGrid=addAlbumGrid()
AlbumGrid.addPhotoBox()
Following is code that works (jsfiddle):
function animal() {
}
animal.prototype = {
canWalk: function () {
return true
},
move: function () {
if(this.canWalk()) {alert ('moving')}
}
}
function bird() {
animal.call(this)
}
var animalProto = Object.create(animal.prototype)
animalProto.constructor = bird
bird.prototype = animalProto
bird.prototype.fly = function () {
animal.prototype.move.call(this)
}
let fluffy = new bird ()
fluffy.fly()
Searching for help I landed at this page, can it be that I am somewhere loosing the context of this, and it is pointing to something I don't want?
In that case, would a solution using composition be an option (object.assign(..))?
Or can it be anything else?
I hope somebody can shed a light.
Thank you...
Ps edit: I have now updated the code, the first 3 comments reflected an older version of this post.
I have a very complex class so i decided to break into sub modules and trying to use revealing modules pattern.
I have main class and decided to divide into smaller container function. but in current scenario
But i am not able to access any internal function from outside i.e callSearchResultWithCallBack using searchFinder.Search.callSearchResultWithCallBack(). which pattern should i use to keep this code clean as well have control to call internal function in sub module.
Thanks
var searchFinder;
function SearchFinder() {
me = this;
this.searchResult = null;
this.init = function() {
declareControls();
createAccordian();
addEvents();
fillControls();
var declareControls = function() {
this.SearchButtons = jQuery('.doSearch');
this.InputLocation = jQuery('#inputLocation');
this.InputDistanceWithIn = jQuery('#inputDistanceWithIn');
this.InputName = jQuery('#inputName');
}
var addEvents = function() {
me.SearchButtons.click(function() {
me.Search();
});
}
var fillControls = function() {
var getGetCategory = function() {
}
}
}
this.Search = function() {
var url = '';
var searchCriteria = {};
validateAndCreateCriteria();
callSearchResultWithCallBack();
function validateAndCreateCriteria() {
function validateAandGetCategory() {
if (SearchValidation.ValidateZipCode(me.InputLocation.val().trim())) {
searchCriteria.location = me.InputLocation.val().trim();
} else if (SearchValidation.ValidateCityState(me.InputLocation.val().trim())) {
searchCriteria.location = me.InputLocation.val().trim();
}
}
}
// need to access it outsite
function callSearchResultWithCallBack() {
me.searchResult(searchCriteria, SearchResultCallBack);
function SearchResultCallBack() {
}
}
}
}
jQuery(function() {
searchFinder = new SearchFinder();
searchFinder.init();
searchFinder.Search.callSearchResultWithCallBack();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
This code has multiple issues, first I will address the fact that for example declareControls is not executing. First declare the function than execute!
this.init = function() {
var declareControls = function() {
this.SearchButtons = jQuery('.doSearch');
this.InputLocation = jQuery('#inputLocation');
this.InputDistanceWithIn = jQuery('#inputDistanceWithIn');
this.InputName = jQuery('#inputName');
}
var addEvents = function() {
this.SearchButtons.click(function() {
me.Search();
});
}
var fillControls = function() {
var getGetCategory = function() {
}
}
declareControls();
//createAccordian(); //not defined
addEvents();
fillControls();
}
Now let's look at others problems that will arise.
the me object referring to this is in the scope of searchFinder and does not refer to the same this in the instance of searchFinder.
function jQuery can be replaced by the commonly used $.
searchFinder.Search.callSearchResultWithCallBack() this is never going to work. Since the Search function is an object and callSearchResultWithCallBack isn't a property of this function.
Solution; make it part of the prototype of Search.
Steps:
Move callSearchResultWithCallBack outside the search function.
Add prototype to Search function
Call function via prototype.
function callSearchResultWithCallBack() {
me.searchResult(searchCriteria, SearchResultCallBack);
function SearchResultCallBack() {
}
}
this.Search.prototype.callSearchResultWithCallBack = callSearchResultWithCallBack;
If you want to fire this function outside of search use this:
searchFinder.Search.prototype.callSearchResultWithCallBack();
Please remember that callSearchResultWithCallBack will throw an error because searchCriteria is undefined.
This fixes your problems for now, but this code has to be revised thoroughly. But this should get you started. http://ejohn.org/blog/simple-javascript-inheritance/
Sorry if my question wasn't clear enough. I'll put my code here...
var chain = {
'fn_1' : {
//fn_1 code here
chain.fn_2();},
'fn_2' : {
//fn_2 code here
chain.fn_3();}
...and so on
}
Let's say if i wana call chain.fn_1(), is there a way I can do that without calling chain.fn_2()?
What I can think of right now is a flag, but that would be alot of excess flags probably for each function. Do you guys have any ideas?
If the series of functions each call the next one you're correct, you'd need to have some sort of flag. In all likelihood, what would be best would be to modify your functions so that they return the reference to the object. Then you could chain like so:
var chain = {
'fn_1': function () {
// do something here.
return this;
},
'fn_2': function () {
// do something here.
return this;
},
'fn_3': function () {
// do something here.
return this;
}
};
// call the full chain:
chain.fn_1().fn_2().fn_3();
// call only the middle.
chain.fn_2();
g.d.d.c's answer is best, but if you can't modify the object for some reason, you could do this:
var _oldFn2 = chain.fn_2
chain.fn_2 = function() { return; };
chain.fn_1();
chain.fn_2 = _oldFn2;
var chain = {
fn : ['fn1', 'fn2', 'fn3'],
call : function(name) {
var i = 0, pos = -1, l = this.fn.length;
for(i = 0; i < l; i += 1) {
if(this.fn[i] == name) {
pos = i;
}
if(pos !== -1) {
this[this.fn[i]]();
}
}
},
fn1 : function() {
alert('fn1');
},
fn2 : function() {
alert('fn2');
},
};
chain.call('fn1'); //chain
chain.fn1(); //single
I have the function below.
Everything works fine except for the Push, Pop and Remove method. These method should be called by the event-handler. This event is fired by the Google Maps API.
The problem is that when the event is fired, these method are not found. I have a "Push is not defined" error message.
I tried with this but that's not working.
How do I call the public method from the event handler?
function Track(mapContainer) {
var map = mapContainer;
var points = new Array();
var isEditMode = false;
var clickListener;
this.Push = function(point) { ... }
this.Pop = function() { ... }
this.Remove = function(point) { ... }
//Enable / disable the marker placements
this.PlaceWaypoint = function(isPlacing) {
if (isPlacing != true) {
if (clickListener != null) {
google.maps.event.removeListener(clickListener);
clickListener = null;
}
} else {
clickListener = map.AddEvent("click", function(event) {
if (!IsDoubleClick()) {
var point = map.PlaceMarker(new WayPoint(event.latLng))
point.RemoveListener(function() { Remove(point); });
Push(point);
} else {
Pop();
}
});
}
}
}
You've got a closure/binding problem. One convention that is frequently used it to assign a variable called self of that, which can later be used in place of this, thanks to the closure properties of JS.
function Track(mapContainer) {
var map = mapContainer,
points = new Array(),
isEditMode = false,
clickListener,
// Make a variable self that points to this, that can be used inside closures
// where the original context is lost
self = this;
this.Push = function(point) { ... }
this.Pop = function() { ... }
this.Remove = function(point) { ... }
//Enable / disable the marker placements
this.PlaceWaypoint =
function(isPlacing) {
if (isPlacing != true) {
if (clickListener != null) {
google.maps.event.removeListener(clickListener);
clickListener = null;
}
} else {
clickListener = map.AddEvent("click", function(event) {
if (!IsDoubleClick()) {
var point = map.PlaceMarker(new WayPoint(event.latLng))
point.RemoveListener(function() { Remove(point); });
// Use the closure reference self instead of this
self.Push(point);
} else {
// Use the closure reference self instead of this
self.Pop();
}
});
};
}
this always refers to the context of the current function, so if you use this in your event handler it refers to that function calls this, not the this in your Track function.
To create a closure that accesses the this of an outer scope, you need to assign that this to a new variable which can be accessed from the inner function:
var self = this;
this.PlaceWaypoint = function(isPlacing) {
// ...
self.Pop();
// ...
}
First of all Pop and Push is not global, second this in the inner scope has another meaning. So you can use closure and rename the "this" to variable of more global scope.
function Track(mapContainer) {
//....
var $this = this;
//Enable / disable the marker placements
this.PlaceWaypoint = function(isPlacing) {
if (isPlacing != true) {
if (clickListener != null) {
google.maps.event.removeListener(clickListener);
clickListener = null;
}
} else {
clickListener = map.AddEvent("click", function(event) {
if (!IsDoubleClick()) {
var point = map.PlaceMarker(new WayPoint(event.latLng))
point.RemoveListener(function() { $this.Remove(point); });
$this.Push(point);
} else {
$this.Pop();
}
});
}
}
}