JQuery making ajax options dynamic - javascript

right now in my $.ajax({ ..}); call I have the following option:
data: { param0: param0, param1: param1}
Say I want the number of parameters to by dynamic (based on a variable passed to the function in which the ajax call is made). How do I provide data: a dynamic set of parameters? I think I need to somehow construct an object (?) ahead of time (i.e. before the ajax call) and then pass this object to data:..but I'm not sure how to do this.
By variable passed in, I mean optional parameters which will be used as the GET params: param2 and param3 if they are passed in. So:
function myAjaxCall(param0, param1, param2, param3) { // param2/3 are optional
$.ajax({
//...
data: { param0: param0, param1: param1} // this will need param2/3 if passed in
//..
});
}
So depending on if param2 and param3 are passed in (either, none or both is valid) I need the data object constructed accordingly.

As you mentioned you need to make an object out of your parameters and pass it as data:
var mydata = {
name: 'ali',
email: 'ali#example.com',
...
}
$.ajax({
...
data: mydata,
...
});

You should make use of the automatically created arguments array.
function myAjaxCall() {
$.ajax({
data: arguments, // "arguments" is an Array Object created automatically by JS
...
});
}
or, if you want it to be an object literal with the arguments array as a property:
function myAjaxCall() {
$.ajax({
data: {args: arguments}, // "arguments" is an Array Object
... // created automatically by JS
});
}
You can call this with any number of parameters, and the parameters can be any data form.
myAjaxCall({ fruit: "apple"}, "blah", 500, true);
Note that arguments is read only, so if you want to work with it, you have to copy it, and arguments.splice(0) will not work.... you have to use a for loop.
To check how many arguments were passed in, simply look at arguments.length.

Related

Understand how knockout is interacting with a javascript object with the push.apply

This is probably yet another javascript scope question with a knockout spin.
Going through the examples in a book that I purchased in which the author presents an example of a single page application but chooses not to completely explain the javascript as it is not the focus of the book.
My question is how does the function in the success action in the ajax call understand the definition for the nested object used as an argument.
outerobj.myarray.push.apply(outerobj.myarray, data.map(function (nestedobj) { nestedobj.prop1 }))
The main object
var outerobj = {
view: ko.observable("View1")
nestedobj : {
prop1 : ko.observable(""),
prop2 : "",
prop3 : ko.observable("")
},
myarray : ko.observableArray([])
}
In a later Ajax/Jquery option there is a call to push.apply with a call like this
var getProperties = function ()
{
$.ajax("/path", {
type: "GET",
success: function (data) {
outerobj.myarray.removeAll();
outerobj.myarray.push.apply(outerobj.myarray, data.map(function(nestedobj) { return nestobj.prop1; }))
outerobj.view("Result");
}
});
}
Array.prototype.push will push values into the 'top' of the array. It can receive a variable number of arguments, such that:
[1].push(2); //[1,2]
[1].push(2, 3); //[1,2,3]
.apply executes a function from the given scope, applying a given array of arguments. It spreads out the array as arguments to the function. For example:
var arr =[];
[].push.apply(arr, [1,2]); // this is equivalent to arr.push(1,2);
Finally, .map returns an array... So basically this is a nice way of pushing an array of items into the array.

How to get keys of Resource object in AngularJS?

I'm new in AngularJS and have some problems with Resource object that is returned by $resource. If I call data['something'], I get what I want. But the problem is that I don't know key and Resource has no .keys() function. How can I solve this? Resource object has only one key, if this helps.
Factory for request:
.factory('StorageRequest', ['$resource',
function ($resource) {
return $resource('/api/storage/:id/query/:queriString', {id: '#id'}, {});
}
]);
Code:
query = "ABC_12345";
StorageRequest.get({"id": $rootScope.selectedData,
"queriString": query}, function (data){
key = ??
$rootScope.values[key] = data[key];
});
Value of data:
Resource {ABC_12345: Array[3], $get: function, $save: function, $query: function, $remove: function…}
Response from the server:
{
- ABC_12345: [
1,
2,
3
]
}
You're actually working too hard :).
The get method will return a reference to an empty object that will be populated once the asynchronous http call to the resource completes.
You're modelling doesn't make a lot of sense to me though. Each value should be keyed to it's unique ID - presumably that's what your selectedData is. With that approach, you already know what the 'key' value should be.
It would look something like this:
query = "ABC_12345";
$rootScope.values[$rootScope.selectedData] = StorageRequest.get({"id": $rootScope.selectedData,
"queriString": query}, function (){
});

Jquery CallBack Parameters

Not sure what I am doing wrong here, but let me setup the scenario.
In the beginning, a store(resultsStore) is being populated with data and being displayed via a function call.
Now, an intermediate step of obtaining more data by way of another store is needed and passing both sets to the original function.
I have tried many variations of the below, but the two datasets do not seem to be passed to the updateLeftPanel function, the first one is there fine, the second says "undefined". Anything obvious I am missing?
resultsStore.load({
params: {
'certid' : certId
},
callback: function(record,operation,success){
updateRightPanel(record[0].data); // code not shown,works fine
//updateLeftPanel(record[0].data); // original call
loadCriteriaStore(record[0].data); // new call
}
});
function loadCriteriaStore(data)
{
criteriaStore.load({
params: {
'edition' : data['Edition']
},
callback: function(record,operation,success,data){
updateLeftPanel(data,record[0].data);
// orig data first, new dataset second
}
});
}
function updateLeftPanel(data, dataa){
// code here
dataa object still unpopulated
}
In the callback in the loadCriteriaStore function, you are assigning 4 parameters. I'm assuming that it only passes 3.
So, in that callback, the data that contains your data is being overwritten by a new "local" data, that's undefined.
function loadCriteriaStore(data)
{
criteriaStore.load({
params: {
'edition' : data['Edition']
},
// Get rid of the ",data" here
callback: function(record,operation,success){
// the `data` param will be the value passed to `loadCriteriaStore`
updateLeftPanel(data,record[0].data);
// orig data first, new dataset second
}
});
}

Firing Events in JavaScript

I have a JavaScript class named 'Item'. 'Item' is defined as shown here:
function Item() { this.create(); }
Item.prototype = {
create: function () {
this.data = {
id: getNewID(),
}
},
save: function() {
$.ajax({
url: getBackendUrl(),
type: "POST",
data: JSON.stringify(this.data),
contentType: "application/json",
success: save_Succeeded,
error: save_Failed
});
},
function save_Succeeded(result) {
// Signal an event here that other JavaScript code can subscribe to.
}
function save_Failed(e1, e2, e3) {
// Signal an event here that other JavaScript code can subscript to.
}
}
Please note, I'm coming from a C# background. So I'm not even sure if what I want to accomplish is possible. But essentially, I want to create an object, subscribe to some event handlers, and attempt to save my object. For instance, I envision doing something like the following throughout my code.
var i = new Item();
i.item_save_succeeded = function() {
// Do stuff when the item has successfully saved
};
i.item_save_failed = function() {
// Do stuff when the item has failed to save
};
i.save(); // start the save process
Is this event-based approach even possible in JavaScript? If so, how? What am I missing? I keep getting a variety of errors that are vague. Because of that, I'm not sure if I'm getting closer or farther away.
If you are using jQuery, you can add an event handler to a custom event type.
The following snippet is taken from the jQuery docs
$('#foo').bind('custom', function(event, param1, param2) {
alert(param1 + "\n" + param2);
});
$('#foo').trigger('custom', ['Custom', 'Event']);
But since jQuery 1.7 deprecates bind, you should use on now. See the jQuery docs for on.
Not 100% sure and I look forward to seeing the answer from a JS pro, but here is what I would do.
Expose some properties within you Item object - namely the functions you wish to be subscribed to.
Upon instancing an item you could then provide callback functions for the events that you wish to be notified of. In your code you could then do something like this:
save: function() {
var self = this;
$.ajax({
url: getBackendUrl(),
type: "POST",
data: JSON.stringify(this.data),
contentType: "application/json",
success: function() { if(typeof(self.success) == "function") self.success(); }
error: function() { if(typeof(self.fail) == "function") self.fail(); }
});
},
In effect, pass the callback functions to the object and let it call them directly when needed. I'm sure someone will now suggest a better way of doing it. :-)

jquery variable scope problem

I have a chat class with two methods: updateChat and sendChat.
//chat.js
var state;
var room;
function Chat (theRoom) {
this.update = updateChat;
this.send = sendChat;
this.room = theRoom;
}
function updateChat(){
alert('ROOM: '+this.room);
$.ajax({
type: "POST",
url: "/chat/process.php",
data: {
'function': 'update',
'state': state,
'room': this.room
},
dataType: "json",
success: function(data){
if(data.text){
for (var i = 0; i < data.text.length; i++) {
$('#chat-area').append($("<p>"+ data.text[i] +"</p>"));
}
}
if(data.state)
state = data.state;
}
});
}
}
//send the message
function sendChat(message, nickname)
{
alert('A'+state); //20
//XXX
updateChat();
alert('B'+state); //20
$.ajax({
type: "POST",
url: "/live-event/chat/process.php",
data: {
'function': 'send',
'message': message,
'nickname': nickname,
'room': this.room
},
dataType: "json",
success: function(data){
alert('C'+state); //wrong!: 2 //it should be 20!
//XXX
updateChat();
alert('D'+state); //21
},
});
}
The constructor of the chat object:
var chat = new Chat(4); //4 = the number of the chat room
chat.send('test', 'tester');
My problem are the method calls at the locations marked with XXX.
In the updateChat() method, this.room is undefined if I call the updateChat methods like that.
But I need to pass the room number to get the right state (state is simply the number of lines in the chat room's text file).
I think it's a problem with variable scope or with the methods not being called in the context of the object.
You need to maintain this when calling those methods, so instead of this:
updateChat();
You can use .call() to maintain context (so this doesn't revert to window inside the called function), like this:
updateChat.call(this);
Or call the method on the object as #casablanca points out below:
this.update();
There also one more issue, this won't be what you want in your $.ajax() callbacks, it'll be the ajax settings object by default, so you need to set the context option to maintain it, like this:
$.ajax({
context: this,
type: "POST",
//...rest of your current options/methods
You may find this easier to grasp if you forget about classes. What you've written there is not a class. There are no classes in JavaScript. You've written a constructor function, but it's of somewhat dubious value because you're assigning the members individually for every instance. The main purpose of constructor functions is to take advantage of prototype-inheritance, so you'd assign the "methods" to the constructor function's prototype.
function Chat (theRoom) {
this.room = theRoom;
}
Chat.prototype.send = sendChat;
Chat.prototype.update = updateChat;
That way, each object created with new Chat(r) will only need to store the room number, and will not need to store the two methods as properties.
Alternatively, just write a createChatRoom function:
var createChatRoom = function(room) {
return {
update: function() {
alert('updating: ' + room);
// ... other stuff
},
sending: function() {
alert('sending: ' + room);
// ... other stuff
}
};
};
The beauty of that is probably obvious: you don't need to prefix anything with this. The room parameter is in scope to the method definitions, and is also truly private (cannot be modified except through calls to the methods. And the caller doesn't have to remember to put new. They just call the function and get back a fresh object with two methods in it.
You can even safely do this:
setTimeout(chatRoom.update, 10);
The update function "knows" what object it is associated with. It never needs to be told which this to use.
This is so convenient and useful, unless I'm expecting to create very large quantities of objects, I don't bother with constructor functions, new, prototype, etc.

Categories

Resources