Returning json object nightwatch.js - javascript

I want to execute json object like this from my html ul list like this
{name: "Nick", surname:"Kyrgios", age: "22", city: "Sydney"}, {....}, {....}
this is the html part
<html>
<ul>
<li class="user">
<div class="name">Nick</div>
<div class="surname">Kyrgios</div>
<div class="age">22</div>
<div class="city">Sydney</div>
</li>
<li class="user odd">
<div class="name">Nick</div>
<div class="surname">Kyrgios</div>
<div class="age">22</div>
<div class="city">Sydney</div>
</li>
</ul>
</html>
my nightwatch js file
browser.elements('css selector','ul li', function (result) {
els = result.value;
var i = 0;
els.forEach(function(el, j, elz){
browser.elementIdText(el.ELEMENT, function(text) {
console.log(text)
})
})
})
This will execute
{ state: 'success',
sessionId: 'cdfdda85-4348-4692-9ad0-2a5d10080a27',
hCode: 151444186,
value: 'Nick\nKyrgios\n22\nSydney',
class: 'org.openqa.selenium.remote.Response',
status: 0 }
{ state: 'success',
sessionId: 'cdfdda85-4348-4692-9ad0-2a5d10080a27',
hCode: 118749018,
value: 'Nick\nKyrgios\n22\nSydney',
class: 'org.openqa.selenium.remote.Response',
status: 0 }
The main question is how can I change it to normal json format like
{name: "Nick", surname:"Kyrgios", age: "22", city: "Sydney"}, {....}, {....}

Every time you run console.log - you are automatically getting a carriage return. Each call to console.log moves you down one line.
You should be appending the results to a string
var jsonString = "";
els.forEach(function(el,j,elz) {
browser.elementIdText(el.ELEMENT, function(text) {
jsonString += text;
})
console.log(jsonString);

Related

KnockoutJS - How to hide certain elements inside foreach using Observable Arrays?

I have a list of WebsiteOwners. I'm trying to build a UI which will display more information about the owners when I click on them.
this.toExpand = ko.observableArray(); //initialize an observable array
this.invertExpand = ko.observable("");
this.invertExpand = function (index) {
if (self.invertExpand[index] == false) {
self.invertExpand[index] = true;
alert(self.invertExpand[index]); //testing whether the value changed
}
else {
self.invertExpand[index] = false;
alert(self.invertExpand[index]); //testing whether the value changed
}
};
Here's the HTML code :
<div data-bind="foreach: WebsiteOwners">
<div>
<button data-bind="click: $root.invertExpand.bind(this,$index())" class="label label-default">>Click to Expand</button>
</div>
<div data-bind="visible: $root.toExpand()[$index]">
Primary Owner: <span data-bind="text:primaryOwner"></span>
Website Name : <span data-bind="text:websiteName"></span>
//...additional information
</div>
</div>
You can store one of your WebsiteOwner items directly in your observable. No need to use an index.
Don't forget you read an observable by calling it without arguments (e.g. self.invertExpand()) and you write to it by calling with a value (e.g. self.invertExpand(true))
I've included 3 examples in this answer:
One that allows only a single detail to be opened using knockout
One that allows all details to be opened and closed independently using knockout
One that does not use knockout but uses plain HTML instead 🙂
1. Accordion
Here's an example for a list that supports a single expanded element:
const websiteOwners = [
{ name: "Jane", role: "Admin" },
{ name: "Sarah", role: "Employee" },
{ name: "Hank", role: "Employee" }
];
const selectedOwner = ko.observable(null);
const isSelected = owner => selectedOwner() === owner;
const toggleSelect = owner => {
selectedOwner(
isSelected(owner) ? null : owner
);
}
ko.applyBindings({ websiteOwners, isSelected, toggleSelect });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: { data: websiteOwners, as: 'owner' }">
<li>
<span data-bind="text: name"></span>
<button data-bind="
click: toggleSelect,
text: isSelected(owner) ? 'collapse' : 'expand'"></button>
<div data-bind="
visible: isSelected(owner),
text: role"></div>
</li>
</ul>
2. Independent
If you want each of them to be able to expand/collapse independently, I suggest adding that state to an owner viewmodel:
const websiteOwners = [
{ name: "Jane", role: "Admin" },
{ name: "Sarah", role: "Employee" },
{ name: "Hank", role: "Employee" }
];
const OwnerVM = owner => ({
...owner,
isSelected: ko.observable(null),
toggleSelect: self => self.isSelected(!self.isSelected())
});
ko.applyBindings({ websiteOwners: websiteOwners.map(OwnerVM) });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: websiteOwners">
<li>
<span data-bind="text: name"></span>
<button data-bind="
click: toggleSelect,
text: isSelected() ? 'collapse' : 'expand'"></button>
<div data-bind="
visible: isSelected,
text: role"></div>
</li>
</ul>
3. Using <details>
This one leverages the power of the <details> element. It's probably more accessible and by far easier to implement!
const websiteOwners = [
{ name: "Jane", role: "Admin" },
{ name: "Sarah", role: "Employee" },
{ name: "Hank", role: "Employee" }
];
ko.applyBindings({ websiteOwners });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: websiteOwners">
<li>
<details>
<summary data-bind="text: name"></summary>
<div data-bind="text: role"></div>
</details>
</li>
</ul>

How to populate multiple JavaScript arrays of objects to HTMLDOM

I am having difficulty to get all the array of objects and display it into HTML lists. Can anyone help me, please. The below is my HTML and JavaScript code. Looking forward to your help.
const allData = [{
date: '2nd',
venue: 'venue1',
location: 'location1',
},
{
date: '3rd',
venue: 'venue2',
location: 'location2',
},
{
date: '4th',
venue: 'venue3',
location: 'location3',
}
]
allData.forEach(data => {
[...document.querySelectorAll('.targets')].forEach(list => {
list.innerHTML = `
<h5 >DATE</h5>
<h4 >${data.date}</h4>
<h5 >VENUE</h5>
<h4 >${data.venue}</h4>
<h5 >LOCATION</h5>
<h4 >${data.location}</h4>
<Button >BUY TICKETS</Button>
`;
})
});
<ul>
<li class="targets"></li>
</ul>
If you change the order of for loops execution and append each string to the previous it works!
const allData = [{
date: '2nd',
venue: 'venue1',
location: 'location1',
},
{
date: '3rd',
venue: 'venue2',
location: 'location2',
},
{
date: '4th',
venue: 'venue3',
location: 'location3',
},
];
const list = document.querySelector('.target')
let innerHTML = '';
allData.forEach(data => {
innerHTML += `
<li>
<h5 class = "shows__date">DATE</h5>
<h4 class = "shows__calander">${data.date}</h4>
<h5 class = "shows__venue-title">VENUE</h5>
<h4 class = "shows__venue">${data.venue}</h4>
<h5 class = "shows__location-title">LOCATION</h5>
<h4 class = "shows__location">${data.location}</h4>
<Button Class = "shows__btn">BUY TICKETS</Button>
</li>
`;
});
list.innerHTML = innerHTML;
<ul class="target">
</ul>
I think you don't need to loop for class='targets' because you only have one li in your html code. It might be better to just get the ul element and then loop allData variable, then change the ul innerHTML on each loop.
HTML Code
<ul></ul>
JS Code:
const allData= [
{
date: '2nd',
venue: 'venue1',
location: 'location1',
},
{
date: '3rd',
venue: 'venue2',
location: 'location2',
},
{
date: '4th',
venue: 'venue3',
location: 'location3',
},
]
let ul = document.querySelector('ul')
let listContent = ''
allData.forEach(data=>{
listContent = listContent +
`
<li>
<h5 >DATE</h5>
<h4 >${data.date}</h4>
<h5 >VENUE</h5>
<h4 >${data.venue}</h4>
<h5 >LOCATION</h5>
<h4 >${data.location}</h4>
<Button >BUY TICKETS</Button>
</li>
`;
});
ul.innerHTML = listContent
Edited based on pilchard comment
The OP provides a basic list structure by the "naked" <ul/> / <li/>
markup.
Thus, there is only a sole <li class="targets"></li> element which can be accessed with a query like '.targets'. Which means, the OP always writes to one and the same element which shows the expected result of a list which features just one element with the data-array's last item-data.
But the <li/> element can be used as a blueprint for creating other list-item elements via <node>.cloneNode which all will be <li class="targets"></li>-alike.
Now one can assign the correct data-item related html content to each newly created list-item clone which also gets appended to its parent list-element ...
const allData = [{
date: '2nd',
venue: 'venue1',
location: 'location1',
}, {
date: '3rd',
venue: 'venue2',
location: 'location2',
}, {
date: '4th',
venue: 'venue3',
location: 'location3',
}];
const venueItemBlueprint = document.querySelector('li.targets');
const venueList = venueItemBlueprint && venueItemBlueprint.parentElement;
if (venueList) {
venueList.innerHTML = '';
allData.forEach(venueData => {
const venueItem = venueItemBlueprint.cloneNode();
venueItem.innerHTML = `
<h5>DATE</h5>
<h4>${ venueData.date }</h4>
<h5>VENUE</h5>
<h4>${ venueData.venue }</h4>
<h5>LOCATION</h5>
<h4>${ venueData.location }</h4>
<Button>BUY TICKETS</Button>`;
venueList.appendChild(venueItem);
});
}
<ul>
<li class="targets"></li>
</ul>

What method to use to access multiple objects in an array?

I'm new to javascript and still learning them.
So I was building a project where I want to display a multiple object, which I put it in an array, to the DOM.
I am not sure what method to use to access the object inside the array.
<div class="container">
<div class="hero">
<h2>List of Names</h2>
</div>
<ul class="name-list"></ul>
</div>
This is my js file:
const nameList = document.querySelector('.name-list');
//List of Names
const john = {
name: 'john',
car: 'fiat',
address: 'new york'
}
const mike = {
name: 'mike',
car: 'toyota',
address: 'sydney'
}
const greg = {
name: 'greg',
car: 'nissan',
address: 'melbourne'
}
//Store list of names in an array
const allNames = [
john,
mike,
greg
]
function displayName (){
//Not sure what methods to use to
return `
<li>
<p>Name: ${allNames.name}</p>
<p>Car: ${allNames.car}</p>
<p>Address: ${allNames.address}</p>
</li>
`
}
So I kind of want to display all the objects in the DOM.
Is it necessary to put the objects in the array first? What methods do I use to return a list in the file? Or do you know any easier methods to display all the objects in the DOM?
Thank you so much for the help.
Maybe you can try something like this :
function showNameList() {
const allNames = [
{
name: 'john',
car: 'fiat',
address: 'new york'
},
{
name: 'mike',
car: 'toyota',
address: 'sydney'
},
{
name: 'greg',
car: 'nissan',
address: 'melbourne'
}
]
var namelist = allNames.map(function (t, i) {
return `<b>Name : </b> ${t.name}<br/><b>Car : </b> ${t.car}<br/><b>Address : </b> ${t.address}<br/><br/>`;
})
document.getElementById('name-list').innerHTML =
'<li>' + namelist.join('</li><li>') + '</li>'
}
showNameList()
<div class="container">
<div class="hero">
<h2>List of Names</h2>
</div>
<ul id="name-list"></ul>
</div>
use map function to display them :
const values = allNames.map(item=>{
return(
<li>
<p>Name: ${item.name}</p>
<p>Car: ${item.car}</p>
<p>Address: ${item.address}</p>
</li>
)
})
<div class="container">
<div class="hero">
<h2>List of Names</h2>
</div>
<ul class="name-list">
{values}
</ul>
</div>

How can I print out HTML markup based on an object hierarchy?

I have a customer list of over 200 on a flat site! I thought perhaps a Javascript object might be good here as it'll enable me to print out the HTML structure dynamically. Is there a way I can quickly build the HTML structure using an object or similar?
<ul class="main-list">
<li class="customer {{SEX}}">
<a href="{{URL}}">
<div>{{Name}}</div>
<img src="/img/{{PATH}}>
</a>
</li>
</ul>
Users: {
1: {
SEX: "male",
URL: "https://google.com",
NAME: "John Smith",
PATH: "/john.jpg"
},
2: {
SEX: "female",
URL: "https://url.com",
NAME: "Emily Smith",
PATH: "/emily.jpg"
},
{
.. so on ..
}
}
How would I be able to loop over the Users object in my markup that prints out the above HTML structure into the main-list div?
const users= {
1: {
SEX: "male",
URL: "https://google.com",
NAME: "John Smith",
PATH: "/john.jpg"
},
2: {
SEX: "female",
URL: "https://url.com",
NAME: "Emily Smith",
PATH: "/emily.jpg"
},
};
const container = document.getElementById('container');
const html = Object.values(users).reduce( (acc, {SEX, URL, NAME, PATH}) => {
return acc + `<div class="customer $SEX}">`
+ `<a href="${URL}">`
+ `<div>${NAME}</div>`
+ `<img src="/img/${PATH}" />`
+ '</a>'
+ '/<div>'
}, '');
container.innerHTML = html;
<div id='container'>
</div>
function makeHTML(obj) {
for(key in obj) {
const item = obj[key]
return `
<div class="customer ${item.SEX}">
<a href="${item.URL}">
<div>{${item.NAME}</div>
<img src="/img/${item.PATH}>
</a>
</div>
`
}
}
usage:
makeHTML(Users); // Returns HTML as string
Like this
I changed to an array
const users = [
{
SEX: "male",
URL: "https://google.com",
NAME: "John Smith",
PATH: "/john.jpg"
},
{
SEX: "female",
URL: "https://url.com",
NAME: "Emily Smith",
PATH: "/emily.jpg"
}
]
const html = users.map(user => `<div class="customer ${user.SEX}">
<a href="${user.URL}">
<div>${user.NAME}</div>
<img src="/img/${user.PATH}>
</a>
</div>`)
document.getElementById("main-list").innerHTML += html.join("")
<div id="main-list"></dov>

Best way to loop Obj data in HTML document with JS?

I'm developing a simple SPA framework. I have a problem. I want to render my Obj data in HTML. Below is my code and my online example
var data = {
for: {
animal: [{
name: 'dog',
alive: 'false'
},
{
name: 'cat',
alive: 'true'
}
],
human: [{
name: 'bob',
sex: 'male'
},
{
name: 'alice',
sex: 'female'
}
]
}
};
<html>
<div id="app">
<ol>
<li np-for="animal">
<np tag="text-for" data="name"></np><br>
<np tag="text-for" data="alive"></np>
</li>
</ol>
</div>
</html>
best way to solve it?
If you are not using a framework, then I suggest you using jQuery, so the full code looks like this
let data = {
animals : [
{ name: 'dog', alive : 'false'},
{ name: 'cat', alive : 'true'}
]
};
let animalList = $('#animals');
data.animals.forEach(function(data) {
animalList.append(`<li>
<b>${data.name}</b>
<i>${data.alive}</i>
</li>`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<div id="app">
<ul id="animals">
<!-- data will automatically generated by jQuery -->
</ul>
</div>
</html>
I suggest you to using let or const for static variable instead of var, read more var vs let vs const in JavaScript
Read more about jQuery

Categories

Resources