I am implementing the following functionality. The majority of the page is created once in my entryPage.php file. The "Stage" table is created through an AJAX call to stageArea.php. My issue is that my data object is created in a $(document).ready(function() {...} which cannot be accessed by my other functions outside of the $(document).ready(function() {...}.
entryPage.php
...HTML...
<script>
$(document).ready(function() {
var dataObject = new DataEntryObj(); // create the data object
$.post("../stageArea.php", {array : dataObject.dataArray}, function(data){
$('#stageArea').html(data);
});
}
var DataEntryObj = function(){
this.dataArray = [[0,0,0,0,0,0,0,3,0]];
....
}
function updateData(value, row, index){
alert("update:" + row + " " + index + " " + value); //values come in OK
alert(dataObject.dataArray[row][index]); // but the data Object isn't here
dataObject.dataArray[row][index] = value; // so this cannot be assigned
$.post("../stageArea.php", {array : dataObject.dataArray}, function(data){
$('#stageArea').html(data);
});
}
</script>
What is a good solution to keep the object in the same scope as the other functions?
Just declare the var outside of $(document).ready and then assign it's value without using var
var dataObject ;
$(document).ready(function() {
dataObject = new DataEntryObj(); // create the data object
......
});
This will now be equivalent to window.dataObject
You can define a global variable, but you should make sure that updateData tries to access dataObject after DOM becomes accessible
var dataObject, DataEntryObj;
DataEntryObj = function(){
this.dataArray = [[0,0,0,0,0,0,0,3,0]];
}
$(document).ready(function() {
dataObject = new DataEntryObj();
$.post("../stageArea.php", {array : dataObject.dataArray}, function(data){
$('#stageArea').html(data);
});
}
function updateData(value, row, index) {
// will have ref to dataObject changed by $(document)
}
You can not access dataObject varailable. Because you setted in function. You should create a global object variable and you can access everywhere.
var dataObject = { data: null };
$(document).ready(function() {
dataObject.data = new DataEntryObj(); // create the data object
$.post("../stageArea.php", {array : dataObject.data.dataArray}, function(data){
$('#stageArea').html(data);
});
}
var DataEntryObj = function(){
this.dataArray = [[0,0,0,0,0,0,0,3,0]];
}
function updateData(value, row, index){
alert("update:" + row + " " + index + " " + value);
alert(dataObject.data.dataArray[row][index]);
dataObject.data.dataArray[row][index] = value;
$.post("../stageArea.php", {array : dataObject.data.dataArray}, function(data){
$('#stageArea').html(data);
});
}
Related
I have page using knockout, which has a searchfield, selectedvalue from a dropdown, and pagenumber..
All these are initialized at set to defaultvalues, especially for first run / page access..
The problem is that i dont understand why i'm getting the following error
"self.selectedTeamId is not a function()"
I know.. this has to be something with the "order of things", so that when it's being used, it has NOT been initialized yet.
Can someone correct my mistake ?
CODE :
$(document).ready(function() {
var ViewModel = function() {
var self = this;
self.photos = ko.observableArray();
self.selectedTeamId = ko.observable(0);
self.searchString = ko.observable('');
self.pageNumber = ko.observable(1);
self.clearFilters = function() {
self.searchString(''); // set default to ''
self.selectedTeamId(0); // set default to 0
self.pageNumber(1); // set default to 1
self.getPhotos();
};
self.getPhotos = function () {
var photoParams = "?teamId=" + self.selectedTeamId() + "&search=" + encodeURIComponent(self.searchString()) + "&pageNumber=" + self.pageNumber();
$.get("api/Photo/GetPhotos" + photoParams,
function(data) {
self.photos(data);
}, "json");
};
};
var photosModel = new ViewModel();
ko.applyBindings(photosModel, document.getElementById("photoarchive"));
// THE NEXT LINE GIVES THE ERROR (self.selectedTeamId())
var photoParams = "?teamId=" + self.selectedTeamId() + "&search=" + encodeURIComponent(self.searchString()) + "&pageNumber=" + self.pageNumber();
$.get("api/Photo/GetPhotos" + photoParams,
function(data) {
photosModel.photos(data);
}, "json");
});
self is a variable which is local to your ViewModel function. It isn't accessible outside of that function.
As you're storing your ViewModel within your photosModel variable, you can instead access the selectedTeamId observable with:
photosModel.selectedTeamId()
You'll need to do the same with self.searchString() and self.pageNumber().
That said, however, you may as well just call photosModel.getPhotos() instead of duplicating the entire function outside of the ViewModel scope.
I have simple situation and can't understand why variable that I pass to function always undefined.
var ProjectItemView = Backbone.Marionette.ItemView.extend({
template: "#ProjectItemTemplate",
initialize: function () {
var id = this.model.get('project_id');
$.getJSON('service/api.php/projects/' + id + '/progress').done(function (data) {
this.renderProgress('4'); //<== pass here
});
},
renderProgress: function (why) {
alert(why); //<== undefined
...
},
...
});
I expect that it equals '4'. In next step I want to pass "data" but now I realize that I can't pass anything.
Since you're invoking renderProgress on the return of $.getJSON you can simply provide the function reference to the done()method of the returned jQuery Promise. Your code would look like this:
var ProjectItemView = Backbone.Marionette.ItemView.extend({
template: "#ProjectItemTemplate",
initialize: function () {
var id = this.model.get('project_id');
$.getJSON('service/api.php/projects/' + id + '/progress')
.done(this.renderProgress);
},
renderProgress: function (data) {
alert(data);
...
},
...
});
If you'll need the view context inside renderProgress (like, for example, to refer to a view property), then provide done() a version of renderProgress that's bound to the view context:
$.getJSON('service/api.php/projects/' + id + '/progress')
.done(_.bind(this.renderProgress, this));
where _.bind is an UnderscoreJS function. Read more about it here.
You loose the context in $.getJSON done callback. Try this:
var ProjectItemView = Backbone.Marionette.ItemView.extend({
template: "#ProjectItemTemplate",
initialize: function () {
var id = this.model.get('project_id');
var _this = this;
$.getJSON('service/api.php/projects/' + id + '/progress').done(function (data) {
_this.renderProgress('4'); //<== pass here
});
},
renderProgress: function (why) {
alert(why); //<== undefined
...
},
...
});
You don't have access to this inside " $.getJSON( " assign this to any variable and then call "renderProgress" method.
var currentObj = this;
$.getJSON('service/api.php/projects/' + id + '/progress').done(function (data) {
currentObj .renderProgress('4'); //<== pass here
});
because in your case this points to current object of that function and not to view object.
So I have some javascript with the following (pseudo) structure. How do I set the this.last_updated variable of the parent function from the showUpdates function, without specifically referencing the name assignment (my_main_function).
var my_main_function = new main()
function main() {
this.last_updated;
function showUpdates(data){
//set this.last_updated=
// do Stuff
}
this.updateMain(){
$.ajax({
url:"/my_url/"
type:"POST",
datatype:"json",
data: {'last_updated':this.last_updated },
success : function(data) { showUpdates(data)},
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText); },
});
}
}
Updated the code base one the comments:
There are two way of creating objects.
If you need to create the object multiple time you will do it like this:
var YourDefintinon = function() {
};
YourDefintinon.prototype.foo = function() {
};
obj1 = new YourDefintinon();
obj2 = new YourDefintinon();
obj1.foo();
If you only need it once in your code you can just do it like that:
var obj = {
};
obj.foo = function() {
};
foo();
So your would need the main only once your code would look like this:
Using Function.prototype.bind (and its polyfill for older browsers) to bind the showUpdates to the obj.
var main = {
last_updated : null
};
function showUpdates(data){
this.last_updated = data.update_time;
}
main.updateMain = function () {
//<< bind showUpdates to `this` and save the bound function in the local variabel showUpdates
var showUpdates = showUpdates.bind(this);
$.ajax({
url:"/my_url/"
type:"POST",
datatype:"json",
data: {'last_updated':last_updated },
success : showUpdates, //<< uses the showUpdates variable not the function
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText);
},
});
};
As you don't want to make showUpdates accessible to others you could wrap the whole block into a function that is immediatly called:
var main = (function() {
var main = {
last_updated : null
};
function showUpdates(data){
this.last_updated = data.update_time;
}
main.updateMain = function () {
var showUpdates = showUpdates.bind(this);
$.ajax({
url:"/my_url/"
type:"POST",
datatype:"json",
data: {'last_updated':last_updated },
success : showUpdates,
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText);
},
});
};
return main;
}());
I Would like to declare a global variable in my JS file and i would like to use that variable in different function in the same class .
I have declared a variable in initialize section
initialize: function () {
this.regionid="";
}
selectItems: function ()
{
this.regionid="10";
this.Regions.url = this.Regions.url() + '?requesttype=1';
this.Regions.fetch({ success: this.renderRegion });
}
renderRegion: function () {
var ddlRegionClass = this.Regions.toJSON();
$(this.el).find('[id=cboRegion] option').remove();
$.each(ddlRegionClass.LOCATIONS_Regions, function (j, cc1) {
var data = 'data='+cc1.AreaCode_2;
var selected = '';
if(cc1.AreaCode_3==this.regionid)
selected="selected";
$('[id=cboRegion]').append('<option value="' + cc1.AreaCode_3 + '" ' + data + selected + ' >' + cc1.Area_Name + '</option>');
})
},
While i am checking the value at
if(cc1.AreaCode_3==this.regionid)
i didnt get the value , it is showing 'undefined'
this.regionid="";
initialize: function () {
//some code
}
I think you have to declare like this..then it will work..you can assign values for variable in any function.
this inside the callback of $.each won't be referring to the view (or the object which the js file is containing).
In the initialize you can bind renderRegion with this:
initialize: function() {
this.regionid = "";
_.bindAll(this, "renderRegion");
}
and inside renderRegion:
renderRegion: function() {
// before doing $.each store 'this' reference
var _this = this;
// and inside the callback use if(cc1.AreaCode_3 == _this.regionid)
}
It should work.
I am writing javascript code with revealing prototype pattern for the first time. I am having problems. When I call add function when user clicks add button then it shows me this error in the console.
Uncaught TypeError: Cannot call method 'add' of undefined
How can I solve this problem?
here is my script.js code
$(function () {
var todo = Todo('contents');
$('.addBtn').on('click', function() {
var name = $(this).parent().find('input[type="text"]').val();
todo.add(name);
});
$('.contents').on('click', '.remove', function() {
var el = $(this).parent();
todo.remove(el);
});
$('.contents').on('click', '.update', function() {
var dom = $(this);
todo.addUpdateField(dom);
});
$('.contents').on('click', '.updateBtn', function() {
var el = $(this);
todo.update(el);
});
});
here is my todo.js code
var Todo = function(c) {
this.contents = $('.' + c);
};
Todo.prototype = function() {
var showel = function (d) {
this.contents.prepend(d);
},
add = function (name) {
if(name != "") {
var div = $('<div class="names"></div>')
.append('<span>' + name + '</span>')
.append("<button class='update' class='update'>Edit</button>")
.append("<button class='remove' name='remove'>Remove</button>");
}
return showel(div);
},
addUpdateField = function (dom) {
var name = dom.parent().find('span').text(),
field = $('<input type="text" value="' + name + '" />'),
update = $('<button class="updateBtn">Update</button>');
dom.parent().html('').append(field).append(update);
return;
},
update = function(el) {
var val = el.parent().find('input').val();
el.parent().html('<span>' + val + '</span>')
.append('<button class="update" class="update">Edit</button>')
.append('<button class="remove" class="remove">Remove</button>');
return;
},
remove = function (el) {
return el.remove();
};
return {
add : add,
update : update,
remove : remove,
addUpdateField : addUpdateField
};
}();
Update
After changing
var todo = Todo('contents');
to
var todo = new Todo('contents');
I get this error
Object [object Object] has no method 'add'
update 2
here is my on jsfiddle
You're not properly constructing your object, so it does not have any of the prototypes:
var todo = Todo('contents');
should be:
var todo = new Todo('contents');
Here is an SO question explaining what is happening when you forget the new.
Edit: the way you are defining your prototype functions is messing up the context (what this points to). Try a pattern like this instead:
Todo.prototype = {
method1: function () { ... },
method2: function () { ... }
};
fixed fiddle: http://jsfiddle.net/BagmY/3/
You're trying to assign Todo's prototype to a self-calling function. However, the prototype is just getting assigned to a function and not the expected return object.
Here's your working fiddle. I assigned the prototype directly to an object with your methods.
Also, JS parses from top to bottom. Therefore, define your new instance of Todo after you declare what Todo is.
This is what a self-calling function should look like:
Todo.prototype = (function() {
// ...
return {
add: add,
update: update,
remove: remove,
addUpdateField: addUpdateField
};
})();