I'm trying to assign values to a javascript object and when doing so, some junk values end up in there which seem like array methods like 'push', 'pop','splice' etc. The following is my code.
function myTest(){
var userArray = new Object();
var req = new Request.JSON({
url: '/myTest.php',
method: 'post',
noCache: true,
data: 'userID=999',
onSuccess: function(json){
for(var key in json){
userArray = json[key];
for (var row in userArray){
alert(row) // This returns values like '$family','push','pop', 'reverse' etc.
}
}
},
onException: function(xhr){
alert("Unable to process your request");
},
onFailure: function(xhr){
alert("Unable to connect to the server");
}
}).send();
}
I am not sure what I'm missing here but it looks like I certainly am. Any help on this would be greatly appreciated.
Never use for...in on an array. Period. The garbage values you are seeing are properties of the array prototype.
See this related question.
for (var row in userArray){
if(userArray.hasOwnProperty(row))
alert(row) ;
}
Details here. Basically, for loop will take all available properties/functions. And you must check if it belongs to that object only or is inherited.
Related
I'm currently experiencing a few problems whilst parsing .JSON.
Ok, so 'element.lineStatuses' can return 1 or 2 opjects in an array but I only want to return the first object from array. I've tried a multitude of different solutions, however, none seem to work...
Please note: I am unable to use '$.first()' as a solution as my application depends on an older version of jQuery.
$.ajax({
url:"https://api.tfl.gov.uk/line/mode/tube,overground,dlr,tflrail/status",
dataType: 'json',
type: 'get',
cache: false,
beforeSend: function() {
$("#loadingDiv").show();
},
success: function(data){
console.log(data);
var jObject = data;
$.each(jObject, function(index, element) {
$("#lines").append("<li class=\"lineName\"><h2>" + element.name + "</h2></li>");
// console.log(element.name);
// element.lineStatuses; can contain 1 or 2 opjects in an array but i only want to return the first objectin array.
var status = element.lineStatuses;
// loop to get line status
// gets all objects
$.each(status, function(index, element) {
var desc = element.statusSeverityDescription;
//console.log(desc);
$("#lines").append("<p class=\"currentStatus\">" + desc + "</p>");
});
});
}// end success
});// end ajax
If you what you want is to get only the first element of an array-like object in an array of its own, you can use slice to create a shallow copy:
var status = [].slice.call(element.lineStatuses, 0, 1);
If you're sure element.lineStatuses is an array and not simply array-like you can use the simpler:
var status = element.lineStatuses.slice(0, 1);
Try this:
var status = element.lineStatuses[0];
I'm having problems with passing two arrays of strings as arguments in JSON format to invoke ASMX Web Service method via jQuery's "POST".
My Web Method is:
[ScriptMethod(ResponseFormat=ResponseFormat.Json)]
public List<string> CreateCollection(string[] names, string[] lastnames)
{
this.collection = new List<string>();
for (int i = 0; i < names.Length; i++)
{
this.collection.Add(names[i] + " " + lastnames[i]);
}
return this.collection;
}
Now, the js:
function CreateArray() {
var dataS = GetJSONData(); //data in JSON format (I believe)
$.ajax({
type: "POST",
url: "http://localhost:45250/ServiceJava.asmx/CreateCollection",
data: dataS,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
//something
}
})
}
GetJSONData() is my helper method creating two arrays from column in a table. Here's the code:
function GetJSONData() {
//take names
var firstnames = $('#data_table td:nth-child(1)').map(function () {
return $(this).text();
}).get(); //["One","Two","Three"]
//take surnames
var surnames = $('#data_table td:nth-child(2)').map(function () {
return $(this).text();
}).get(); //["Surname1","Surname2","Surname3"]
//create JSON data
var dataToSend = {
names: JSON.stringify(firstnames),
lastnames: JSON.stringify(surnames)
};
return dataToSend;
}
Now, when I try to execude the code by clicking button that invokes CreateArray() I get the error:
ExceptionType: "System.ArgumentException" Message: "Incorrect first
JSON element: names."
I don't know, why is it incorrect? I've ready many posts about it and I don't know why it doesn't work, what's wrong with that dataS?
EDIT:
Here's dataToSend from debugger for
var dataToSend = {
names: firstnames,
lastnames: surnames,
};
as it's been suggested for me to do.
EDIT2:
There's something with those "" and '' as #Vijay Dev mentioned, because when I've tried to pass data as data: "{names:['Jan','Arek'],lastnames:['Karol','Basia']}", it worked.
So, stringify() is not the best choice here, is there any other method that could help me to do it fast?
Try sending like this:
function CreateArray() {
var dataS = GetJSONData(); //data in JSON format (I believe)
$.ajax({
type: "POST",
url: "http://localhost:45250/ServiceJava.asmx/CreateCollection",
data: {names: dataS.firstnames,lastnames: dataS.surnames} ,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
//something
}
})
}
This should work..
I think since you are already JSON.stringifying values for dataToSend property, jQuery might be trying to sending it as serialize data. Trying removing JSON.stringify from here:
//create JSON data
var dataToSend = {
names : firstnames,
lastnames : surnames
};
jQuery will stringify the data when this is set dataType: "json".
Good luck, have fun!
Altough, none of the answer was correct, it led me to find the correct way to do this. To make it work, I've made the following change:
//create JSON data
var dataToSend = JSON.stringify({ "names": firstnames, "lastnames": surnames });
So this is the idea proposed by #Oluwafemi, yet he suggested making Users class. Unfortunately, after that, the app wouldn't work in a way it was presented. So I guess if I wanted to pass a custom object I would need to pass it in a different way.
EDIT:
I haven't tried it yet, but I think that if I wanted to pass a custom object like this suggested by #Oluwafemi, I would need to write in a script:
var user1 = {
name: "One",
lastname:"OneOne"
}
and later pass the data as:
data = JSON.stringify({ user: user1 });
and for an array of custom object, by analogy:
data = JSON.stringify({ user: [user1, user2] });
I'll check that one later when I will have an opportunity to.
This is what I have so far, essentially I'd like to use the data to instantiate a new info-window from google maps api dynamically from the data response. I know so far that I'm pushing objects to an array(which are two different data types), but if that's the only wrong here. Then how can I dynamically add the response into an object so I can retrieve data with a loop?
var i, venues, allVenues=[];
$.ajax({
url: 'url',
dataType: 'json',
data: 'data'
async: true,
success: function(data) {
venues = data['response']['groups'][0]['items'];
JSON.parse(venues);
for(i in venues){
allVenues.push(venues[i]);
}
};
/*Do something realistic with data other than logging it to console*/
console.log(allVenues);
You do it right, but not in the right place. jQuery.ajax will not wait for the response, but will invoke a 'success' callback when the request is answered.
Try this:
var i, venues, allVenues=[];
$.ajax({
url: 'url',
dataType: 'json',
data: 'data'
async: true,
success: function(data) {
venues = data['response']['groups'][0]['items'];
// The following line of code does nothing, because you
// did not store it's return value. Fortunately it wasn't
// even needed
//
// JSON.parse(venues);
for(i in venues) {
allVenues.push(venues[i]);
}
// or
// allVenues.push.apply(allVenues, venues);
// or in ES6
// allVenues.push(...venues);
// or the following will create a new array instance and save it in the allVenues variable
// allVenues = allVenues.concat(venues);
/*Do something realistic with data other than logging it to console*/
console.log("Here are your updated venues:");
console.log(allVenues);
}
});
console.log("These are your old venues:");
console.log(allVenues);
EDIT:
You can check that the identity of the allVenues array didn't change by printing it to the console every second:
setInterval(function(stored) {
console.log(stored);
console.log(stored === allVenues);
}, 1000, allVenues);
EDIT:
To update an array to contain only the items of another array, you can use:
allVenues.length = 0;
allVenues.push.apply(allVenues, venues);
or
allVenues.length = venues.length;
for (var i in venues) {
allVenues[i] = venues[i];
}
By using SP.ClientContext from Javascript end, below is the code i used to "UPDATE" a list item. Simply:
var clientContext = new SP.ClientContext( siteURL );
spList = clientContext.get_web().get_lists().getByTitle( myListName );
this.spList_ExistingItem = spList.getItemById( itemID );
spList_ExistingItem.set_item( 'FullName', myFullName );
spList_ExistingItem.set_item( 'Age', myAge );
spList_ExistingItem.update();
clientContext.executeQueryAsync(succeeded_handler, fail_handler);
This allows me to update an list item by querying it by ONE condition which is: getItemById(itemID) here.
Now let's say i want to delete any item which is:
Age = 30
Country = US
Then how do i do such query with multiple conditions. And then even to DELETE please?
UPDATED
According to the answer below, i found the REST API is more easier and cleaner to use for Client/Javascript end, compared to CSOM. (So then, of course i changed all my codes to the REST API way already.)
So the conclusion is, i suggest to use REST API rather than CSOM (SP.ClientContext).
Thanks! :)
This can be done in two different ways, either by using CSOM/JSOM or via the SharePoint REST API. Since you are using the CSOM/JSOM model in your question, I'll only show you how it's done using that method.
Using CSOM/JSOM
To filter SP.ListItem's on mulitple conditions, there are no single methods that take the arguments as multiple filter fields. Instead, you'll have to resort to using a CAML query to specify the list items you want, as below.
var clientContext = new SP.ClientContext( siteURL );
spList = clientContext.get_web().get_lists().getByTitle( myListName );
//Create a CAML-query with your filter conditions
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><Where><And><Eq><FieldRef Name=\'Age\'/>' +
'<Value Type=\'Number\'>30</Value></Eq>
<Eq><FieldRef Name=\'Country\'/>' +
'<Value Type=\'Text\'>US</Value></Eq></And></Where></Query><RowLimit>10</RowLimit></View>');
//The query will return a collection of items matching your conditions
this.collListItem = spList.getItems(camlQuery);
clientContext.load(collListItem);
//Execute the query
clientContext.executeQueryAsync(function () {
var itemCount = collListItem.get_count();
//For each list item in the collection, mark it to be deleted
for (var i = itemCount - 1; i >= 0; i--) {
var oListItem = collListItem.itemAt(i);
oListItem.deleteObject();
};
//Execute the delete operation
clientContext.executeQueryAsync(deleteSucceeded, deleteFailed);
}, fail_handler);
Using SharePoint REST API
This method assumes that you use jQuery to be able to do some simple $.ajax() calls and use the promise functionality, since you might have multiple items to delete. It also assumes that you understands how you can use jquery deferred objects to chain asynchronous functions to run in sequence.
The simple idea is to
Make a request to the REST api and get all the items matching your filter conditions
For each object in the collection returned, make another request that deletes the item, and add the request to an array of requests
When all requests are done, do whatever you want!
Note that you might have to modify the REST api call to match your columns. Just use the browser or Postman to check that your request is correct.
function getItemsToDelete () {
//You might have to modify this so it filters correctly on your columns
var requestUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle(" + myListName + ")/items?$filter=Age eq 30 and Country eq 'US'")
//Return and ajax request (promise)
return $.ajax({
url: requestUrl,
type: "GET",
headers: {
"accept": "application/json;odata=verbose",
},
success: function(result) {
$.each(result.d.results, function(index, item){
//Note that we push the ajax-request to the array
//that has been declared a bit down
itemsToDelete.push(deleteItem(item));
});
},
error: function(error) {
//Something went wrong when retrieving the list items
}
});
}
function deleteItem (item) {
//All SP.ListItems holds metadata that can be accessed in the '__metadata' attribute
var requestUrl = item.__metadata.uri;
return $.ajax({
url: requestUrl,
type: "POST",
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"IF-MATCH": item.__metadata.etag,
"X-HTTP-Method": "DELETE"
},
success: function() {
console.log("Item with ID " + item.__metadata.id + " successfully deleted!");
},
error: function(error) {
//Something went wrong when trying to delete the item
}
});
}
//Declare an array of deferred objects that hold a delete request
//for each item that is to be deleted
var itemsToDelete = [];
//First get the items to delete
$.when(getItemsToDelete()).then(function () {
$.when.apply($, itemsToDelete).then(function(){
console.log("All items are deleted!");
});
});
Some useful sources
jQuery Deferred object
CRUD operations on list items with SharePoint REST api
I have the following JSON object:
new Ajax.Request(url, {
method: 'post',
contentType: "application/x-www-form-urlencoded",
parameters: {
"javax.faces.ViewState": encodedViewState,
"client-id": options._clientId,
"component-value": options._componentValue
}
});
Now, I would like to be able to append to the "Parameters" object programattically, but I am unsure of how I would actually do this.
you can simply assign to it. But you might want to do that before creating the request.
var parameters = {
"javax.faces.ViewState": encodedViewState,
"client-id": options._clientId,
"component-value": options._componentValue
}
parameters.foo = 'bar';
var myAjax = new Ajax.Request(url, {
method: 'post',
contentType: "application/x-www-form-urlencoded",
parameters: parameters
});
Assume that the JSON object is named as obj in the Ajax.Request Javascript function. You could now add to the parameters object like this:
obj['parameters']['someproperty'] = 'somevalue';
Hope this helps
You can't append to it after you call new, because Prototype automatically sends and starts processing the Ajax request upon creation, instead do something like this if you need to alter the parameters object:
var params = {
"javax.faces.ViewState": encodedViewState,
"client-id": options._clientId,
"component-value": options._componentValue
// Either add your additional properties here as:
// propertyName : propertyValue
};
// Or add your properties here as:
// params.propertyName = propertyValue;
new Ajax.Request(url, {
method: 'post',
contentType: "application/x-www-form-urlencoded",
parameters: params
});
Here's a solution I used to append to the JSON object's existing data attribute, but I needed it to be generic enough to handle different key-value pairs. Here's what I created based on this post which seems to work for me.
doAction : function(mData){
this.data = mData;
this.appendData = function(mDataToAppend){
var jsonStrAr = JSON.stringify(mDataToAppend).replace('{','').replace('}','').split('","');
for(var v = 0; v < jsonStrAr.length; v++){
var m = jsonStrAr[v].split(':');
this.data[m[0].replace(/"/g,'')] = m[1].replace(/"/g,'');
}
}
}
The result is a single JSON object with n to many attributes, which can then be sent over to the server via the JSON.stringify() command in the ajax request. Still getting comfortable/thinking with JSON, so there might be a better way to do this - in which case, I'm all ears.