Get value from nested JavaScript object in CasperJS - javascript

I'm trying to dig into a nested javascript array to grab the first instance of an object. Here's the code:
var utils = require('utils');
var casper = require('casper').create();
casper.start('http://en.wikipedia.org/wiki/List_of_male_tennis_players', function() {
this.echo(this.getTitle());
// Get info on all elements matching this CSS selector
var tennis_info_text = this.evaluate(function() {
var nodes = document.querySelectorAll('table.sortable.wikitable tbody tr');
return [].map.call(nodes, function(node) { // Alternatively: return Array.prototype.map.call(...
return node.textContent;
});
});
// Split the array into an array of object literals
var tennis_data = tennis_info_text.map(function(str) {
var elements = str.split("\n");
var data = {
name : elements[1],
birth : elements[2],
death : elements[3],
country : elements[4]
};
return data;
});
// Dump the tennis_names array to screen
utils.dump(tennis_data.slice(1,5));
});
casper.run();
The result of stdout is this:
{
"name": "Acasuso, JoséJosé Acasuso",
"birth": "1982",
"death": "–",
"country": " Argentina"
},
{
"name": "Adams, DavidDavid Adams",
"birth": "1970",
"death": "–",
"country": " South Africa"
},...
For the name element, I'm getting everything from the tr row, which matches 2 elements when you look at the target url source. What I want is just the second part of the name element with class "fn"; for instance: "David Adams", "José Acasuso". I'm thinking something like name:elements[1].smtg should work, but I've had no luck.
Additionally, how would I print the available object keys from the elements object?

The problem is that the first cell contains two elements which contain the name and first name of the player with different ordering. When taking the textContent of the whole cell, both name representations are put into the same string, but in the browser only one of them is visible. If you want only to access the visible one, you need to explicitly crawl it.
You could write a custom function that removes the duplicate name from the string, but it is easier to just take the correct element's textContent.
This can be easily done in the page context:
var tennis_data = this.evaluate(function() {
var nodes = document.querySelectorAll('table.sortable.wikitable tbody tr');
return [].map.call(nodes, function(node) {
var cells = [].map.call(node.querySelectorAll("td"), function(cell, i){
if (i === 0) {
return cell.querySelector(".fn").textContent;
} else {
return cell.textContent;
}
});
return {
name: cells[0],
birth: cells[1],
...
}
});
});
Additionally, how would I print the available object keys from the elements object?
elements is an array of strings so there are no keys that you can access besides the array indexes and array functions.

Related

How to get only 1st element of JSON data?

I want to fetch only 1st element of json array
my json data :
{
id:"1",
price:"130000.0",
user:55,
}
{
id:"2",
price:"140000.0",
user:55,
}
i want to access the price of 1st json element
price : "13000.0"
my code
$.each(data_obj, function(index, element) {
$('#price').append(element.price[0]);
});
but my output
is '1'
Assuming that you have array of objects
var arr = [{
id:"1",
price:"130000.0",
user:55,
},
{
id:"2",
price:"140000.0",
user:55,
}]
console.log(arr[0].price)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You data isn't valid JSON, JSON data key must be wrap within double quote, but your data isn't wrapped in double quote
var data = [{
"id":"1",
"price":"130000.0",
"user":55
},{
"id":"2",
"price":"140000.0",
"user":55
}]
console.log(data[0]["price"]);
Hello You just need to add [] from starting and ending point of your json string. see here var data = JSON.parse( '[{ "id":"1","price":"130000.0","user":55},{"id":"2","price":"140000.0","user":55}]');
var priceValue = 0;
$.each(data, function(index, element) {if(index == 0){ priceValue = element.price;}});console.log(priceValue);
Your answer will be 13000.0
The element having the your JSON data means, we can able to use below code to get the first JSON data.
element[0].price
Thanks,
You are using for each loop and in function you get 2 params first one is index and second is the element itself. So this will iterate through all elements.
$.each(data_obj, function(index, element) {
$('#price').append(element.price);
});
If you just want to get first element
$('#price').append(data_obj[0].price);
var my_first_json_obj = data_obj[0]; // Your first JSON obj (if it's an array of json object)
var my_price = my_first_json_obj.price; // Your price
$('#price').append(my_price);
If you want only the first item's price, you don't need a loop here.
$('#price').append(data_obj[0].price);
would work here.
For further reading you can refer here
Following is the solution worked for my problem
I use return false;
$.each(data_obj, function(index, element) {
$('#price').append(element.price[0]);
return false;
});
Which gives only 1st value of array elements.

JS form validation using JSON for rules

I'm developing some client side form validation that needs to use a JSON file (that is shared with server side validation) that contains arrays of id keys (to describe the input type) and rules (to define what the validation rules are for the input type).
Here is an example of the JSON structure:
[
{
"id": "search",
"rules": [
{
"name": "min_length",
"value": 5
},
{
"name": "email"
}
]
},
{
"id": "phone-number",
"rules": [
{
"name": "min_length",
"value": 5
}
]
}
]
I am doing the following:
Loading the file and parsing the json and storing as an object.
Looping through the form and storing all id's.
What I need help with
Match each form element "id" with a corresponding "id" value in the json object
Create a function for each "rules" "name".
When a form element with an "id" that is matched in the JSON object, run the functions that match each "rules" "name" for the matched "id". So looking at the JSON I have above I would want to" Check the form for an element with "search" and then run a function to check the min length and run a function that checks the email (check against a regex I have).
Ideally I want to keep this as generic as possible to allow for any id + rules to be dealt with. The rules themselves will be a pre defined list of "min_length", "email" etc so these can be functions that run if the rule exists.
Here is some JS code that I have so far. It's more of a few ideas that haven't got me closer to what I need to do!
// Get the json file and store
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'js/rules.json');
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
// Load json...
loadJSON(rulesData);
// Global vars...
var rules = [];
function rulesData(data) {
// Parse json and create object...
var jsonObj = JSON.parse(data);
// Push objects to rules array for later use
for (var i = 0; i < jsonObj.length; i++) {
rules.push(jsonObj[i]);
}
}
$(function(){
$('#email-submit').click(function(){
var formInputs = new Array();
//Get the form ID
var id = $(this).parent().attr('id');
$('#' + id + ' input').each(function(){
//Get the input value
var inputValue = $(this).val();
//Get the input id
var inputId = $(this).attr('id');
//Add them to the array
formInputs[inputId] = inputValue;
});
console.log(formInputs);
return false;
});
});
var emailRegex = "^[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$";

How to iterate an array of objects and print out one of its properties

I have the following code in a display template in sharepoint, I have an array of objects and I need to have the following result.
Name1
Name2
Name3
So I can replace the default rendering of sharepoint multiple people user field with a tooltip.
However, I dont know how to iterate and then concatenate:
Screenshot:
Code:
// List View - Substring Long String Sample
// Muawiyah Shannak , #MuShannak
(function () {
// Create object that have the context information about the field that we want to change it's output render
var projectTeamContext = {};
projectTeamContext.Templates = {};
projectTeamContext.Templates.Fields = {
// Apply the new rendering for Body field on list view
"Project_x0020_Team": { "View": ProjectTeamTemplate }
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(projectTeamContext);
})();
// This function provides the rendering logic
function ProjectTeamTemplate(ctx) {
var projectTeamValue = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];
//newBodyvalue should have the list of all display names and it will be rendered as a tooltip automaticlaly
return "<span title='" + projectTeamValue + "'>" + newBodyValue + "</span>";
}
You can "map" property values from the projectTeamValue array objects into a new array, then "join" those values together (using ", " as the separator in this example) all in one go:
var newBodyValue = projectTeamValue.map(function(person) {
return person.value;
}).join(", ");
If your projectTeamValue array looked like:
[{ value: "Name1" }, { value: "Name2" }, { value: "Name3" }]
Then newBodyValue would be:
"Name1, Name2, Name3"
jsFiddle Demo
Side note: Array.prototype.map() was not available in IE 8 and below but should work in every other browser.

Javascript arrays or object

I wish to grab content from various sources, using different API calls, and collate them all into an object or array with the same format. I am getting stuck with javascript arrays and objects, and none of the examples I find seem to do what I want to do. This is the format I want to store. This is pseudo coded for an example of what I want to achieve
var content = new Object();
getTweets();
getSoundCloud();
display();
function getTweets() {
//first result
content.type = "tweet
content.text = "the text of the tweet"
content.image = "the image from the tweet"
return content;
}
function getSoundCloud() {
//second result
content.type = "soundcloud
content.text = "the name of the song"
content.image = "the image of the song"
return content;
}
function display() {
//for each content
{
$("#container").append(content.text);
}
}
The first result is generated by one function call, and the Second result is generated by a different function call.
I want these functions to add all of the content together into the same format object. Once the object is populated, I wish to iterate it in a different function and display on the screen.
How do I make this object? I have tried it but the data is always the same, ie, overwritten with the same values. In php this would be an associative array perhaps or something like
I want to have an object for each piece of content I have, and can loop through it
content[0].type = "tweet"
content[1].type = "coundcloud"
Any suggestions with examples would be great.
Many Thanks
When you have many of something you should immediately think
I need to store these things in an array.
When your "things" are complex and have various properties/ state, you should immediately think:
I need to create an object to store them.
... so what would be best here is an array of objects. Each function will create objects and add them to content, which we'll switch to an array:
var content = []; // Array
getTweets();
getSoundCloud();
display();
function getTweets() {
var tweet = {}; // This is an object
tweet.type = "tweet";
tweet.text = "The text of the tweet";
tweet.image = "The image of the tweet";
content.push(tweet); // add the object to the array.
}
function getSoundCloud() {
var soundcloudThing = {};
soundcloudThing.type = "soundcloud"
soundcloudThing.text = "the name of the song"
soundcloudThing.image = "the image of the song"
content.push(soundcloudThing);
}
Now when it comes to showing this content, as have an array; the obvious thing to do here is iterate over it;
function display() {
for (var i=0;i<content.length;i++)
{
$("#container").append(content[i].text);
// You can also use content[i].image and content[i].type in here
}
}
Note that [] and {} is literal notation for creating arrays and objects. It's use is favoured over new Array() and new Object().
I have done an example here: http://jsfiddle.net/pdXsA/2/
var content = [];
content.push(getTweets());
content.push(getSoundCloud());
display();
function getTweets() {
return{
type : "tweet",
text : "the text of the tweet",
image : "the image from the tweet"
};
}
function getSoundCloud() {
return{
type : "soundcloud",
text : "the name of the song",
image : "the image of the song"
};
}
function display() {
content.forEach(function(item){
$("#container").append(item.text +"<br/>");
});
}​
content should be an array of objects, each function adds its object into the content array :
var content = []; // empty array
getTweets();
getSoundCloud();
display();
function getTweets() {
content.push ({ //first result
type: "tweet",
text: "the text of the tweet",
image: "the image from the tweet"
});
}
function getSoundCloud() {
content.push ({ //second result
type: "soundcloud",
text: "the name of the song",
image: "the image of the song"
});
}
function display() {
content.forEach (v) {
// code to format the object v appropriately
var vtext = v.type + ' : ' + v.text;
$("#container").append(vtext);
}
}
Actually, just sussed it out like this
var content = {
text: this.text.linkify().linkuser().linktag(),
image: this.profile_image_url,
type: 'tweet'
};
arrayContent.push(content);
I can now loop through it, and each Content and display it!

CasperJS getElementsByXPath only returning first element

I use the following code to get all table cells in the first table row. I'd like to then check the innerHTML of every single table cell. But in the object returned by this function only the first table cell is actually there, all the other properties are null:
firstRow = this.evaluate(function () {
return __utils__.getElementsByXPath('//tbody/tr[1]/td');
});
utils.dump(firstRow);
The output from utils.dump is:
[
{
"abbr": "",
"align": "",
"attributes": {...}
},
null,
null,
null
]
I also tried with utils.findAll and it was the same. How can I get all the matched elements?
With Casper/PhantomJS evaluate() functions, you have to map native DOM elements and lists of elements to something JSON-serializable:
var firstRow = this.evaluate(function () {
var elements = __utils__.getElementsByXPath('//tbody/tr[1]/td');
return [].map.call(elements, function(element) {
return element.outerHTML;
});
});
utils.dump(firstRow);

Categories

Resources