I'm trying to create a JSON index of a particular section of HTML. Here is the HTML that I have:
<div class="box span12">
<div class="row-fluid">
<div class="item span12" data-width-helper="12"></div>
</div>
<div class="row-fluid">
<div class="box span6">
<div class="row-fluid">
<div class="item span12" id="4" data-width-helper="12"></div>
</div>
<div class="row-fluid">
<div class="box span6">
<div class="row-fluid">
<div class="item span12" id="6" data-width-helper="12"></div>
</div>
<div class="row-fluid">
<div class="item span12" id="7" data-width-helper="12"></div>
</div>
</div>
<div class="item span6" id="5" data-width-helper="6"></div>
</div>
</div>
<div class="item span6" data-width-helper="6"></div>
</div>
<div class="row-fluid">
<div class="item span8" id="2" data-width-helper="8"></div>
<div class="item span4" id="3" data-width-helper="4"></div>
</div>
</div>
Ultimately, I'd like to end up with JSON that looks like this:
[
[
{
"id":1,
"width":12
}
],
[
{
"width":6,
"items":
[
[
{
"id":4,
"width":12
}
],
[
{
"width":6,
"items":
[
[
{
"id":6,
"width":12
}
],
[
{
"id":7,
"width":12
}
]
]
},
{
"id":5,
"width":6
}
]
]
},
{
"id":8,
"width":6
}
],
[
{
"id":2,
"width":8
},
{
"id":3,
"width":4
}
]
]
So basically, each box holds an array of rows, which holds an array of items, which are objects with a little descriptive information. I can't seem to wrap my head around a recursive function that will build out that json object so that there can be boxes instead of items going down unlimited levels.
Hopefully someone smarter than me can take the time to help out - I'd really appreciate it. And as a side note, I'm fine with using jQuery and/or Underscore.js
I'm not entirely sure how you want the function to work, so I just wrote a bit of psuedocode for you. The goal here was to make every tag into an array of its children, unless the tag was an item, in which case, it creates an object with "width" and "id" instead.
function toJSON(element)
var returnObject;
switch
case: item
returnObject = {
"id": elementId,
"width": elementWidth
};
break;
case: default
returnObject = [];
for each child
returnObject.push(toJSON(child));
break;
return returnObject;
Related
I have a HTML list with rearrangable divs, they can be moved up and down, once rearranged I need to change the array with the same order of the HTML elements.
HTML:
<div id="List">
<div id="listUnit2" class="row">
<div class="text-center" style="width:50px;">
<p>Orange</p>
</div>
</div>
<div id="listUnit1" class="row">
<div class="text-center" style="width:50px;">
<p>Pear</p>
</div>
</div>
<div id="listUnit0" class="row">
<div class="text-center" style="width:50px;">
<p>Apple</p>
</div>
</div>
</div>
Array:
"listArray": [
{
"id": 0,
"name": "apple",
},
{
"id": 1,
"name": "pear",
},
{
"id": 2,
"name": "orange",
},
]
How can I get this result using the id value as a reference?
"listArray": [
{
"id": 2,
"name": "orange",
},
{
"id": 1,
"name": "pear",
},
{
"id": 0,
"name": "apple",
},
]
I tried:
var unitsRows = document.querySelectorAll("#list .row");
var newList = [];
for (var row of unitsRows) {
var rowId = row.id
rowId = rowId.replace('listUnit', "");
var newEl = listArray[rowId];
newList.push(newEl);
}
listArray = newList;
The order of the objects changes but it's not the same of the HTML after some rearrangmet.
You can do this every time it changes.
I had to fix your invalid markup
const listArray = [...document.querySelectorAll("#List .row")]
.map(row => ({ id: +row.id.match(/\d+/g), name: row.querySelector('div').textContent.trim() }))
console.log(listArray)
<div id="List">
<div id="listUnit2" class="row">
<div class="text-center" style="width:50px;">
<p>Orange</p>
</div>
</div>
<div id="listUnit1" class="row">
<div class="text-center" style="width:50px;">
<p>Pear</p>
</div>
</div>
<div id="listUnit0" class="row">
<div class="text-center" style="width:50px;">
<p>Apple</p>
</div>
</div>
</div>
You can get the list on UI, then you sort the listArray based on it.
listArray.sort(function (a, b) {
return names.indexOf(a.name) - names.indexOf(b.name);
});
I updated your code and print the result in the console. You can check it:
var listArray = new Array({
"id": 0,
"name": "apple",
}, {
"id": 1,
"name": "pear",
}, {
"id": 2,
"name": "orange",
});
var unitsRows = document.querySelectorAll(".row p");
var names = [];
[].forEach.call(unitsRows, function(item) {
names.push(item.innerHTML.toLowerCase());
});
listArray.sort(function (a, b) {
return names.indexOf(a.name) - names.indexOf(b.name);
});
console.log('Result', listArray);
<div id="List">
<div id="listUnit2" class="row">
<div class="text-center" style="width:50px;">
<p>Orange</p>
</div>
</div>
</div>
<div id="listUnit1" class="row">
<div class="text-center" style="width:50px;">
<p>Pear</p>
</div>
</div>
</div>
</div>
<div id="listUnit0" class="row">
<div class="text-center" style="width:50px;">
<p>Apple</p>
</div>
</div>
</div>
</div>
1- Your html code is wrong, modify the structure.
2- You have an element with id='List', not an element with class=list. And you need the children of that div, So modify your selector:
var unitsRows = document.querySelectorAll("#List .row");
3- Get text of p element with:
let text = document.querySelectorAll(`#${itm.id} p`)[0].textContent.trim();
var unitsRows = document.querySelectorAll("#List .row");
let newList = [];
unitsRows.forEach(itm => {
let text = document.querySelectorAll(`#${itm.id} p`)[0].textContent.trim();
newList.push({
id: itm.id.replace('listUnit', ""),
text
})
})
console.log(newList)
<div id="List">
<div id="listUnit2" class="row">
<div class="text-center" style="width:50px;">
<p>Orange</p>
</div>
</div>
<div id="listUnit1" class="row">
<div class="text-center" style="width:50px;">
<p>Pear</p>
</div>
</div>
<div id="listUnit0" class="row">
<div class="text-center" style="width:50px;">
<p>Apple</p>
</div>
</div>
</div>
I'm starting to learn vue, I was trying to practice a little bit and i got stuck with the for-loops.
I'm making a call to an api I've developed to understand better the data handling. The output of the call is:
[
{
"_id": "ID1",
"customerID": "ASDF",
"purchases": [
{
"laptop": "DELL",
"price": "500"
},
{
"monitor": "DELL",
"price": "200"
}
]
},
{
"_id": "ID2",
"customerID": "FDSA",
"purchases": [
{
"laptop": "MacBook",
"price": "1800"
},
{
"monitor": "DELL",
"price": "300"
}
]
}
]
The purpose I have is to use v-for to go through the array of purchases, so that it can display the contents of the array for each entry in the json.
The vue template I'm using is:
<template>
<div>
<div class="card" v-for="data in purchases" :key="data.purchases">
<div class="card-image">
<div class="card-content">
<div class="media">
<div class="media-content">
<p class="title is-4">PURCHASES</p>
<div
class="columns is-variable is-1-mobile is-0-tablet is-3-desktop is-8-widescreen is-2-fullhd"
>
<div class="column">Laptop: {{data.purchases[0].laptop}}</div>
<div class="column">Monitor: {{data.purchases[0].monitor}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
Script in the vue file:
<script>
import { ref } from "#vue/composition-api";
export default {
setup() {
const purchases = ref([]);
const API_url = "http://localhost:8383/purchases";
async function getData() {
const reponse = await fetch(API_url);
const json = await reponse.json();
purchases.value = json;
console.log(purchases);
}
getData();
return {
purchases,
};
},
};
</script>
I know I'm only showing the first element of the array and that's precisely my question, how can I go through the whole array with the v-for.
I would very much appreciate the help :)
Create another nested v-for to loop through data.purchases :
<template>
<div>
<div class="card" v-for="data in purchases" :key="data.purchases">
<div class="card-image">
<div class="card-content">
<div class="media">
<div class="media-content">
<p class="title is-4">PURCHASES</p>
<div
class="columns is-variable is-1-mobile is-0-tablet is-3-desktop is-8-widescreen is-2-fullhd"
>
<template v-for="purchase in data.purchases">
<div class="column">Laptop: {{purchase.laptop}}</div>
<div class="column">Monitor: {{purchase.monitor}}</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
I have a nested ng-repeat like this. I have a scope variable boards which is array and has further nesting with another array called tasks which is again an array. As you can see in the inner ng-repeat I am trying to bind to task.content.
<div class="col-md-3 boards topmargin leftmargin" ng-repeat="board in boards">
<div class="row">
<div class="col-md-12 centerText bordered"><b>{{board.title}}</b></div>
</div>
<div class="row topmargin tasksContainer">
<div class="col-md-12">
<p ng-init="tasks = board.tasks" ng-repeat="task in tasks" ng-init="taskIndex=$index">
<div>
<span>{{taskIndex}}</span>
<span>{{task.content}}</span>
</div>
</p>
</div>
<hr>
</div>
<div class="row topmargin addTask">
<div class="col-md-12"><textarea class="addTaskField" placeholder="enter task here....."
ng-model="newTask.content"></textarea></div>
<button class="btn btn-primary btn-block" ng-click="addNewTask(board)">Add Task</button>
</div>
</div>
This is the structure of boards array
// vars
$scope.boards = [];
$scope.board={
title: "",
tasks: []
};
$scope.newTask = {
content: "",
tags: [],
completed: null
};
I push the newTask object into board.tasks and board object in boards array which is working fine and on debugger boards array look like this
$scope.boards = [
{
title : "shopping",
tasks : [
{
content: "pen",
complete: false,
tags: []
},
{
content: "bread",
complete: true,
tags: ['groceries']
}
]
},
{
title : "tomorrow",
tasks : [
{
content: "go swimming",
complete: false,
tags: []
},
{
content: "complete to-do app",
complete: false,
tags: ['urgent']
}
]
}
];
The problem I am facing is that the binding {{task.content}} and {{taskIndex}} are not displaying. What am I doing wrong?
A few of things here:
The link that EProgrammerNotFound linked to in the comments (a <p> tag cannot contain a <div> tag)
Second, your ng-repeat is missing boards: ng-repeat="task in board.tasks". So, I think it's supposed to look like this:
<div class="col-md-3 boards topmargin leftmargin" ng-repeat="board in boards">
<div class="row">
<div class="col-md-12 centerText bordered"><b>{{board.title}}</b></div>
</div>
<div class="row topmargin tasksContainer">
<div class="col-md-12">
<div ng-repeat="task in board.tasks" ng-init="taskIndex=$index">
<div>
<span>{{taskIndex}}</span>
<span>{{task.content}}</span>
</div>
</div>
</div>
<hr>
</div>
<div class="row topmargin addTask">
<div class="col-md-12">
<textarea class="addTaskField" placeholder="enter task here....." ng-model="newTask.content"></textarea>
</div>
<button class="btn btn-primary btn-block" ng-click="addNewTask(board)">Add Task</button>
</div>
</div>
Another thing is your <p> tag with the ng-repeat has two ng-inits. Not sure what that results in :)
Example here https://plnkr.co/edit/yJ7u4YTu2TAfhFajAjUY
I have an object with array of data in {}, I want to print name attribute of all params.
The object is:
[
{
"name": "Chris",
"value": 10000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
},
{
"name": "Estafanie",
"value": 14000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
},
{
"name": "Paul",
"value": 20000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
}
]
I want to see in my html:
Chris, Estefanie, Paul
I try with:
{{# _.each(name, function(listname){ }}
<div class="col-md-3 col-sm-4 col-xs-4">
<div class="names">
<h5>{{{ listname }}}</h5>
</div>
</div>
{{# }) }}
But not working ;/ I find in mustache documentation but I don't see nothing same.
Anybody can help me with this?.
Thanks
Your view doesn't look like a MustacheJS view. Amend it to look like the following. Substitute "ObjectLiteralName" for the name of your object literal variable name.
Using {{#}}{{/}} in a Mustache view denotes that you wish to loop over an object.
See MustacheJS. It contains all the information you need to get up and running with Mustache.
View
<div id="target">Loading...</div>
<script id="template" type="x-tmpl-mustache">
{{#ObjectLiteralName}}
<div class="col-md-3 col-sm-4 col-xs-4">
<div class="names">
{{name}}
</div>
</div>
{{/ObjectLiteralName}}
</script>
Javascript
function renderTemplate() {
var $template = $('#template').html();
Mustache.parse($template); // optional, speeds up future uses
var rendered = Mustache.render($template, ObjectLiteralName);
$('#target').html(rendered);
}
Result
<div class="col-md-3 col-sm-4 col-xs-4">
<div class="names">
Chris
</div>
</div>
<div class="col-md-3 col-sm-4 col-xs-4">
<div class="names">
Estefanie
</div>
</div>
<div class="col-md-3 col-sm-4 col-xs-4">
<div class="names">
Paul
</div>
</div>
How can I use ng-repeat to loop over data that contains many nested array data?
I have data that will have many "Segments"
Example:
confirm.booking.flightData[0].Segments[0].FlightNumber
confirm.booking.flightData[0].Segments[1].FlightNumber
confirm.booking.flightData[0].Segments[2].FlightNumber
I have done both ng-repeat with angular, and without angular I would end up resorting to javascript that loops over data and creates the html dynamically, but I wish to do this the ANGULAR way.. HOW?
HTML with Angular/Javascript Arrays:
<div class="container-fluid">
<div class="row">
<div class="col-md-4">
<span style="font-weight: bold;">Flight</span>
</div>
<div class="col-md-4">
<span style="font-weight: bold;">Departs</span>
</div>
<div class="col-md-4">
<span style="font-weight: bold;">Arrives</span>
</div>
</div>
<div class="row">
<div class="col-md-4">
{{confirm.booking.flightData[0].Segments[0].FlightNumber}}
</div>
<div class="col-md-4">
({{confirm.booking.flightData[0].Segments[0].DepartureAirport}})
</div>
<div class="col-md-4">
({{confirm.booking.flightData[0].Segments[0].ArrivalAirport}})
</div>
</div>
</div>
Nesting can be done in repeats, but repeating too much in ng-repeats can be costly in terms of performance as angular creates scopes for each element repeated. Hence, filtering data till the perfect abstracted values that you need in terms of html should be done in the js file.
For eg: if u need only segements in the html form do this, or if u need even flight data in html form follow #Rachel's post
<ul data-ng-repeat="item in confirm.booking.flightData[0].Segments">
<li>{{ item.FlightNumber}}</li>
</ul>
Let's say your data is in flightdetails, then you can go about it like this:
<div ng-repeat="a in flightdetails ">
<div ng-repeat="b in a.booking">
<div ng-repeat="c in b.flightdata">
<div ng-repeat="d in c.segments">
{{d.flightnumber}}
</div>
</div>
</div>
</div>
You can use nested ng-repeat to bind your data - see a demo below:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.confirm = {
booking: {
flightData: [{
Segments: [{
FlightNumber: 1
}, {
FlightNumber: 2
}]
}, {
Segments: [{
FlightNumber: 3
}, {
FlightNumber: 4
}]
}]
}
}
// console.log($scope.confirm);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="wrapper" ng-app="app" ng-controller="ctrl">
<div ng-repeat="x in confirm.booking.flightData">
Data {{$index + 1}}:
<div ng-repeat="y in x.Segments">
<div>Flight No: {{y.FlightNumber}}</div>
</div>
<br/>
</div>
</div>
If you want to display only the following:
confirm.booking.flightData[0].Segments[0].FlightNumber
confirm.booking.flightData[0].Segments[1].FlightNumber
confirm.booking.flightData[0].Segments[2].FlightNumber
then you can use limitTo - see demo below:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.confirm = {
booking: {
flightData: [{
Segments: [{
FlightNumber: 1
}, {
FlightNumber: 2
}]
}, {
Segments: [{
FlightNumber: 3
}, {
FlightNumber: 4
}]
}]
}
}
// console.log($scope.confirm);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="wrapper" ng-app="app" ng-controller="ctrl">
<div ng-repeat="x in confirm.booking.flightData | limitTo : 1">
Data {{$index + 1}}:
<div ng-repeat="y in x.Segments">
<div>Flight No: {{y.FlightNumber}}</div>
</div>
<br/>
</div>
</div>
I created an example here:
http://codepen.io/ackzell/pen/ENBymo
It ultimately looks like this, but check the pen as it has some more info:
<ul>
<li ng-repeat="flight in vm.flightData">
<ul>
<li ng-repeat="segment in flight.Segments">
<em>FlightNumber</em> {{ segment.FlightNumber }}
<br />
<em>Departure:</em> {{ segment.DepartureAirport }}
<br />
<em>Arrival:</em> {{ segment.ArrivalAirport }}
</li>
</ul>
</li>
</ul>
Nesting ng-repeats would help, but maybe you want to give your data some treatment first.