I'm having difficulty generating a json object in the below format from the data below. Fiddle
[ { Invoice:
{
headers: { date: "15-01-2020", buyer: "McDonalds", order: "145632"},
items: { name: "Big Mac", quantity: "5", rate: "20.00"},
items: { name: "Small Mac", quantity: "10", rate: "10.00"}
}
}
, { Invoice: { // Other invoices go here, I've used just one for this example} }
]
<div class="invoice">
<div class="header">
<div contenteditable data="date">15-Jan-2020</div>
<div contenteditable data="buyer">McDonalds</div>
<div contenteditable data="order">145632</div>
</div>
<div class="item">
<div contenteditable data="name">Big Mac</div>
<div contenteditable data="quantity">5</div>
<div contenteditable data="rate">20.00</div>
</div>
<div class="item">
<div contenteditable data="name">Small Mac</div>
<div contenteditable data="quantity">10</div>
<div contenteditable data="rate">10.00</div>
</div>
</div>
<button>Loop</button>
jQuery
var button = $("button")
button.on("click",function() {
jsonObj =[];
$('.invoice>.header>div, .invoice>.item>div').each(function(index,item) {
console.log($(this).parent().attr('class'));
console.log($(this).attr('data'),$(this).text());
q = {}
q ['header'] = $(this).parent().attr('class');
q [$(this).attr('data')] = $(this).text();
jsonObj.push(q);
});
console.log(jsonObj);
console.log(JSON.stringify(jsonObj));
});
I current end up with an object like this where the keys are repeated everywhere. How can I get this right?
[ { "header": "header", "date": "15-Jan-2020"}
, { "header": "header", "buyer": "McDonalds"}
, { "header": "header", "order": "145632"}
, { "header": "item", "name": "Big Mac"}
, { "header": "item", "quantity": "5"}
, { "header": "item", "rate": "20.00"}
, { "header": "item", "name": "Small Mac"}
, { "header": "item", "quantity": "10"}
, { "header": "item", "rate": "10.00"}
]
In your example, you have an object with two same keys:
"items":{
"name":"Big Mac",
"quantity":"5",
"rate":"20.00"
}
"items":{
"name":"Small Mac",
"quantity":"10",
"rate":"10.00"
}
This won't work, because you can only have one, so you need to change the value of items key to an array of objects:
"items":[
{
"name":"Big Mac",
"quantity":"5",
"rate":"20.00"
},
{
"name":"Small Mac",
"quantity":"10",
"rate":"10.00"
}
]
The iteration code may look like this:
const jsonObj = [];
$('.invoice').each((index, item) => {
const invoice = {
header: {},
items: []
};
$(item).find('.header > div').each((index, item) => {
const key = $(item).attr('data');
invoice.header[key] = $(item).text();
});
$(item).find('.item').each((index, item) => {
const itemObj = {};
$(item).find('div').each((index, item) => {
const key = $(item).attr('data');
itemObj[key] = $(item).text();
});
invoice.items.push(itemObj);
});
jsonObj.push({
Invoice: invoice
});
});
The main difference from your version is that it iterates through the dom step by step. First, through each invoice, then through each header of the invoice and each item. This way it's easy to build the desired structure.
Here's the jsfiddle link: https://jsfiddle.net/tara5/tanb174h/
Pure JS code for this:
Remarks : I have changed:
<div ... data="..."> ... </div>
to
<div ... data-ref="..."> ... </div>
to be conform with HTML directives (see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-* )
const jsonObj = []
, inVoices = document.querySelector('.invoice')
, subDivOf = (parent,query) => [...parent.querySelectorAll(query)]
, dataElms = (ac,el)=>{ac[el.dataset.ref]=el.textContent;return ac }
;
Loop.onclick=_=>
{
jsonObj.push( { Invoice: getInVoicesValues() } )
console.clear()
console.log( jsonObj )
}
function getInVoicesValues()
{
const headers = subDivOf(inVoices,'.header>div').reduce(dataElms,{})
, items = subDivOf(inVoices,'.item').reduce((accI,itm)=>
{
accI.push( subDivOf(itm, 'div').reduce(dataElms,{}))
return accI
},[])
;
return { headers, items }
}
.as-console-wrapper {
max-height: 100% !important;
width: 70% !important;
top: 0; left: 30% !important;
}
div.invoice>div:before {
display: block;
content: attr(class) ' :';
}
div[contenteditable] {
font: 12px Arial, Helvetica, sans-serif;
margin: .3em;
width: 12em;
border : 1px solid grey;
padding:.2em 1em;
margin-left:6em;
}
div[contenteditable]::before {
display: inline-block;
content: attr(data-ref);
font-weight : bold;
width: 4.9em;
margin-left:-5.3em;
}
<div class="invoice">
<div class="header">
<div contenteditable data-ref="date">15-Jan-2020</div>
<div contenteditable data-ref="buyer">McDonalds</div>
<div contenteditable data-ref="order">145632</div>
</div>
<div class="item">
<div contenteditable data-ref="name">Big Mac</div>
<div contenteditable data-ref="quantity">5</div>
<div contenteditable data-ref="rate">20.00</div>
</div>
<div class="item">
<div contenteditable data-ref="name">Small Mac</div>
<div contenteditable data-ref="quantity">10</div>
<div contenteditable data-ref="rate">10.00</div>
</div>
</div>
<button id="Loop">Loop</button>
.........................run snippets full screen for better view
second method
const jsonObj = [];
const inVoicesElms = document.querySelectorAll('.invoice div');
Loop.onclick=_=>
{
jsonObj.push( { Invoice: getInVoicesValues() } )
console.clear()
console.log( jsonObj )
}
function getInVoicesValues()
{
let rep = { headers:{}, items:[] }
, cur = null
;
inVoicesElms.forEach(el =>
{
if (el.matches('.header'))
{
cur = rep.headers
}
else if (el.matches('.item'))
{
cur = {}
rep.items.push(cur)
}
else // (el.matches('[contenteditable]'))
{
cur[el.getAttribute('data')] = el.textContent
}
})
return rep
}
.as-console-wrapper { max-height: 100% !important; width: 70% !important;
top: 0; left: 30% !important;
}
<div class="invoice">
<div class="header">
<div contenteditable data="date">15-Jan-2020</div>
<div contenteditable data="buyer">McDonalds</div>
<div contenteditable data="order">145632</div>
</div>
<div class="item">
<div contenteditable data="name">Big Mac</div>
<div contenteditable data="quantity">5</div>
<div contenteditable data="rate">20.00</div>
</div>
<div class="item">
<div contenteditable data="name">Small Mac</div>
<div contenteditable data="quantity">10</div>
<div contenteditable data="rate">10.00</div>
</div>
</div>
<button id="Loop">Loop</button>
Related
First of all, I'm sorry to write in English not well.
I'm looking foward to find the answer to fix this problems.
I'm making a todolist, it had a problem that the class ('centerLine') keeps following next element
after deleting an array to use splice.
Please someone know, let me know how to fix it.
Thank you
https://github.com/seongjin2427/Public
* checked the check box
*after pushing x-box to get rid of checked todo
You can send id to method
#click="deleteTask(todo.id)"
and then filter array
deleteTask(id) {
this.todos = this.todos.filter(t => t.id !== id)
}
let app = new Vue({
el: '#app',
data: {
todos: [{
id: 1,
text: '밥 먹기',
checked: false
},
{
id: 2,
text: '잘 자기',
checked: false
},
{
id: 3,
text: '유튜브 보기',
checked: false
}
],
input_text: ""
},
methods: {
addTodo() {
// 배열 길이 변수 저장
let arrayLength = this.todos[this.todos.length-1].id;
// Add 버튼 눌렀을 때, input_text값 그대로 배열에 push 하기
if (this.input_text != "") {
this.todos.push({
id: arrayLength + 1,
text: this.input_text
});
}
// push후 input 값 초기화
this.input_text = "";
},
change1(e) {
// 할 일 클릭 후 input 창으로 변경
let index = e.target.id.substr(3, 3);
document.querySelector('#vsb' + index).classList.toggle('none');
document.querySelector('#invsb' + index).classList.toggle('none');
},
change2(e) {
// input 창에서 마우스가 out되면 실행할 것
let index = e.target.id.substr(5, 3);
document.querySelector('#vsb' + index).classList.toggle('none');
document.querySelector('#invsb' + index).classList.toggle('none');
},
deleteTask(id) {
this.todos = this.todos.filter(t => t.id !== id)
}
}
});
#app li {
list-style: none;
padding:0;
margin: 0;
}
span.centerLine {
text-decoration: line-through;
color: gray;
}
.x-box {
border-radius: 30%;
opacity: 0%;
}
.x-box:hover {
opacity: 100%;
transition: all 1s;
}
.none {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<body>
<div id="app">
<h1>To Do List</h1>
<hr>
<input type="text" v-model="input_text" #keyup.enter="addTodo">
<input type="button" value="Add" #click="addTodo">
<br>
<div class="todo-box">
<ul>
<li v-for="(todo, idx) in todos" :key="idx">
<input :id="'chk'+(idx+1)" type="checkbox" v-model="todo.checked">
<span :id="'vsb'+(idx+1)" #click="change1" :class="{'centerLine': todo.checked}">{{ todo.text }}</span>
<input :id="'invsb'+(idx+1)" #mouseout="change2" class="none" type="text" v-model="todo.text">
<input :id="'xbox'+(idx+1)" class="x-box" #click="deleteTask(todo.id)" type="button" value="x">
</li>
</ul>
</div>
</div>
</body>
you can send the task in the method
#click="deleteTask(task)"
then splice it from array
deleteTask(task) {
this.todos.splice(this.todos.indexOf(task),1)
}
So the JSON I need to use is structured like this:
[
{
"result":"OK",
"message":"Display",
"value":200,
"rows":29
} ,
[
{
"personID":1,
"img_path":"/1234/",
"img":"00001.jpg"
},
{
"personID":2,
"img_path":"/1234/",
"img":"00002.jpg"
},
]
]
How do it get JUST this part?:
personID: 1
img_path: /1234/
img: 00001.jpg
Here's what I'm doing currently, which is outputs the full JSON... (exactly as it's shown in the first codeblock I added... the one that was showing how the JSON is structured).
var fullURL = the_URL_where_Im_getting_the_json
function readTextFile(file, callback)
{
var rawFile = new XMLHttpRequest();
rawFile.overrideMimeType("application/json");
rawFile.open("GET", file, true);
rawFile.onreadystatechange = function() {
if (rawFile.readyState === 4 && rawFile.status == "200")
{
callback(rawFile.responseText);
}
}
rawFile.send(null);
}
readTextFile(fullURL, function(text){
var data = JSON.parse(text);
console.log(data);
}
);
I appreciate you time and help. Thanks.
Trying to access this via indexes doesn't seem too robust. If you know the shape is going to be consistent with this type of output, you can deconstruct the data into info and results and then iterate over them. If you know what identifier you are looking for, for example, you can use find.
I have extended this example a bit to try to show how using functions like map and find can work over larger sets of data, as whatever project you are working on gets bigger. Front-end frameworks like React do a lot of this stuff for you.
const data = [{
"result": "OK",
"message": "Display",
"value": 200,
"rows": 29
},
[{
"personID": 1,
"img_path": "/1234/",
"img": "00001.jpg"
},
{
"personID": 2,
"img_path": "/1234/",
"img": "00002.jpg"
},
]
]
const [info, results] = data;
document.getElementById('information').innerHTML = Object.entries(info).map(([key, value]) => `
<div>
<span class="key">${key.toUpperCase()}:</span>
<span class="value">${value}</span>
</div>`).join('');
document.getElementById('results').innerHTML = results.map(result => {
return `<div>ID: ${result.personID}, path: ${result.img_path}</div>`
}).join('');
document.getElementById('find').addEventListener('keyup', function() {
document.getElementById('target').innerHTML = (results.find(result => result.personID == this.value) || {
img: 'Not Found'
}).img
})
.cards {
display: flex;
}
.card {
box-shadow: 1px 1px 10px;
padding: 16px;
width: 25%;
margin: 6px;
}
.card-title {
font-size: 2em;
border-bottom: 1px solid black;
padding: 6px 6px 6px 0px;
}
.card-content {
display: flex;
flex-direction: column;
align-items: space-between;
}
.card-content>div {
margin: 6px;
display: flex;
justify-content: space-between;
}
input {
width: 50px;
}
<div class="cards">
<div class="card">
<div class="card-title">
Information
</div>
<div id="information" class="card-content"></div>
</div>
<div class="card">
<div class="card-title">
All People
</div>
<div id="results" class="card-content"></div>
</div>
<div class="card">
<div class="card-title">
Find IMG
</div>
Person ID:
<input id="find" />
<div id="target" class="card-content" />
</div>
</div>
I really feel the data in your file should be modified for consistency.
For now you can do this:
//loop through this if you want data of all objects in the 2nd item i.e data[1][0...n]
var objectData = data[1][0]
var personID = objectData.personID
var img = objectData.img
var img_path = objectData.img_path
I'm trying to create a vue component but whenever I want to hide some elements with v-show it doesn't work.
When you click any element on the list I want to hide it and on the click event element.visible is set to false, so in the component template I bind that value to v-show but it wont hide.
I guess it's because element.visible it's kind of nested attribute but I'm not really sure.
var collection = [
{ id: 1, name: 'element 1' },
{ id: 2, name: 'element 2' },
{ id: 3, name: 'element 3' },
{ id: 4, name: 'element 4' },
{ id: 5, name: 'element 5' },
{ id: 6, name: 'element 6' },
{ id: 7, name: 'element 7' },
{ id: 8, name: 'element 8' },
];
var multiselect = {
props: ['collection'],
data: function() {
return {
subscribed: [],
toSubscribe: [],
toUnsubscribe: [],
dataset: []
}
},
mounted: function(){
this.dataset = _.map(this.collection, function(element){
element.visible = true;
return element;
});
},
methods: {
subscribe: function(element){
element.visible = false;
}
}
}
new Vue({
el: '#app',
components: {
'multiselect': multiselect
},
data: {
elements: collection
}
})
.multiselect .list {
border: 1px solid #000;
height: 215px;
max-height: 215px;
overflow: scroll;
}
.multiselect .list .list-element {
text-align: center;
padding: 0.2em;
cursor: pointer;
}
.multiselect .list .list-element:hover {
background-color: #d6dbdf;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js"></script>
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<div id="app">
<multiselect inline-template :collection="elements">
<div class="col-sm-12 multiselect">
<div class="col-sm-5 list">
<div class="col-sm-12">
<div v-for="element in dataset" class="list-element" #click="subscribe(element)" v-show="element.visible">
{{element.name}}
</div>
</div>
</div>
<div class="col-sm-2">
<button class="btn btn-primary btn-fill">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</button>
<button class="btn btn-primary btn-fill">
<i class="fa fa-arrow-left" aria-hidden="true"></i>
</button>
</div>
<div class="col-sm-5 list">
</div>
</div>
</multiselect>
</div>
As an interesting variation, you don't need to clone the collection elements or set a property on them.
It is enough to have a parallel array of flag, but you have to be careful of the syntax to update them and the flag must be contained in an object in order to be observable.
i.e an array of { visible: true } rather than an array of true.
Ref: Mutation-Methods
var collection = [
{ id: 1, name: 'element 1' },
{ id: 2, name: 'element 2' },
{ id: 3, name: 'element 3' },
{ id: 4, name: 'element 4' },
];
var multiselect = {
props: ['collection'],
data: function() {
return {
visibleFlags: []
}
},
created: function(){
this.collection.forEach(x => {
this.visibleFlags.push({visible: true}); // Vue mutation method
})
},
methods: {
subscribe: function(index){
this.$set(this.visibleFlags, index, false)
}
}
}
new Vue({
el: '#app',
components: {
'multiselect': multiselect
},
data: {
elements: collection
}
})
.multiselect .list {
border: 1px solid #000;
height: 125px;
max-height: 215px;
overflow: scroll;
}
.multiselect .list .list-element {
text-align: center;
padding: 0.2em;
cursor: pointer;
}
.multiselect .list .list-element:hover {
background-color: #d6dbdf;
}
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<div id="app">
<multiselect inline-template :collection="elements">
<div class="col-sm-12 multiselect">
<div class="col-sm-5 list">
<div class="col-sm-12">
<div v-for="(element, index) in collection"
class="list-element" v-show="visibleFlags[index].visible"
#click="subscribe(index)">
{{element.name}}
</div>
</div>
</div>
</div>
</multiselect>
</div>
The problem is that you are modifying an already-responsive object. Vue cannot detect property additions.
It's obscured by the fact that you're copying via map, and assigning it to a new array, but it's an array of references to responsive objects, to each of which you have added the visible property. If you examine the data items in the parent, you'll see that it gets visible added, too.
The minimal fix is to use Object.assign to create a new object and copy properties into it. This way all properties are inserted into a non-responsive object, which is then made responsive during assignment.
mounted: function(){
this.dataset = _.map(this.collection, function(element){
return Object.assign({}, element, {visible: true});
});
},
You could do this in created, since you don't need the DOM element.
I have several elements that are displayed as <li> elements in a loop. For each element I want behavior such that when the element is clicked a modal box opens up. Inside the modal box I want contents that are specific to the element that was clicked.
The data below shows all the elements:
{value: 10, name: "foo"},
{value: 12, name: "bar"},
{value: 14, name: "foobar"},
{value: 22, name: "test"},
{value: 1, name: "testtooo"},
{value: 8, name: "something"}
When I click on an element, I want to see the value property for it inside the modal box.
I've created a fiddle for this: https://jsfiddle.net/hvb9hvog/14/
Question
I've gotten the modal working, however, how can I show each elements value property inside the modal?
I am sure there are multiple ways to go about this, but one way would be to create a new data property, let's call it value. When you #click the li you get it's value, set it to the value property and display that value property in the body of the modal ({{this.value}}).
You can have two #click methods, so create another one that updates the data property you just created, called value.
Here's a fiddle
Relevant code changes:
In your li element:
<li v-for="request in filteredRequests">
{{request.name}}
</li>
In your modal markup:
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
<div slot="body">
{{this.value}}
</div>
</modal>
In vue data:
data: {
requests: [
{value: 10, name: "foo"},
{value: 12, name: "bar"},
{value: 14, name: "foobar"},
{value: 22, name: "test"},
{value: 1, name: "testtooo"},
{value: 8, name: "something"}
],
num: 0,
showModal: false,
value: 9999999999
},
In vue methods:
methods: {
setVal(val) {
this.value = val;
}
},
Vue.component('modal', {
template: '#modal-template'
})
var vm = new Vue({
el: "#app",
data: {
requests: [{
value: 10,
name: "foo"
},
{
value: 12,
name: "bar"
},
{
value: 14,
name: "foobar"
},
{
value: 22,
name: "test"
},
{
value: 1,
name: "testtooo"
},
{
value: 8,
name: "something"
}
],
num: 0,
showModal: false,
value: 9999999999
},
methods: {
setVal(val) {
this.value = val;
}
},
computed: {
c: function() {
return `Slider Number: (${this.num})`
},
filteredRequests() {
return this.requests.filter(r => r.value > this.num)
}
},
});
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transition: opacity .3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
transition: all .3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://unpkg.com/vue#2.3.4/dist/vue.js"></script>
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<div id="app">
<div class="form-horizontal">
<div class="form-group">
<label class="col-md-2 control-label">色</label>
<div class="col-md-10">
<input class="form-control" v-model="c" :style="{backgroundColor: c}" />
<div class="help-block">
<input type="range" min="0" max="360" v-model.number="num" />
<ul class="ml-thumbs">
<li v-for="request in filteredRequests">
{{request.name}}
</li>
</ul>
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
<div slot="body">
{{this.value}}
</div>
</modal>
</div>
</div>
</div>
</div>
</div>
Add "req" property to data
data() {
return {
...
req: {},
...
}
}
set click event:
{{request.name}}
add body slot
...
<h3 slot="header">custom header</h3>
<div slot="body">
{{req.value}}
</div>
...
https://jsfiddle.net/w4e6hr86/
I'm not sure if you are asking this using Vue.js or just JS. So, here are my answers (basic examples). I recommend you to read about event delegation + events on vuejs.
Vue Js
<template>
<div class="content">
<ul>
<li v-for="item in items" #click.prevent="showModal(item)">{{ item }}</li>
</ul>
<div class="modal" v-show="isModalVisible">
{{ JSON.stringify(selectedItem) }}
close modal
</div>
</div>
</template>
<script>
export default {
name: 'something',
data () {
return {
selectedItem: item,
items: [{
id: 1,
name: 'something'
}, {
id: 2,
name: 'something #2'
}]
}
},
computed: {
isModalVisible () {
return this.selectedItem !== null
}
}
methods: {
showModal (item) {
this.selectedItem = item
}
}
}
</script>
Plain javascript
const toggleModal = content => {
const $body = document.querySelector('body')
const $modal = $body.querySelector('.modal')
$modal && $modal.remove()
$body.insertAdjacentHTML('beforeend',`<div class="modal">${content}</div>`)
}
document.querySelector('ul').addEventListener('click', e => {
if (! e.target.matches('li')) {
return
}
toggleModal(e.target.innerText)
});
About Event delegation.
About insertAdjacentHtml.
About Vuejs Event handling
Could anyone point me a more easy-to-read-and-expand way of doing this:
data = {/*very very long json*/};
var inHTML = "";
jQuery.each(data, function(key, value){
var articleUrl = 'url-to-somewhere';
var newItem = "<div class='item'><div class='item--poster'><img src='"+data[key].backdropUrl+"' alt='title'/></div><div class='item--content'><h2>"+data[key].title+"</h2><ul><li>"+data[key].productionYear+"</li><li>"+data[key].productionCountry+"</li></ul></div><div class='item--link'><p><a class='' href='"+articleUrl+"'>Lue lisää</a></p></div></div>";
inHTML += newItem;
});
jQuery("#container").html(inHTML);
What I'm looking for is something similar to ng-repeat of Angular.
I would bet on using placeholder template and .clone(). What exactly you need to do is, create a Master DOM like this:
<div id="master-dom" class="item">
<p><strong>Name</strong> <span class="Name"></span></p>
<p><strong>Age</strong> <span class="Age"></span></p>
</div>
Now give a CSS that would hide the Master DOM:
#master-dom {display: none;}
The next attempt would be, have a #content area:
<div id="content"></div>
And now comes the JavaScript part.
var data = [
{
"name": "Praveen",
"age": 27
},
{
"name": "Jon Skeet",
"age": 29
},
{
"name": "Kumar",
"age": 25
}
];
Having the above as the data structure, you can loop through and insert:
$.each(data, function (i, v) {
// We need the v.
$("#master-dom").clone()
.removeAttr("id")
.find(".Name").text(v.name).end()
.find(".Age").text(v.age).end()
.appendTo("#content");
});
See the final output here:
$(function() {
var data = [{
"name": "Praveen",
"age": 27
}, {
"name": "Jon Skeet",
"age": 29
}, {
"name": "Kumar",
"age": 25
}];
$.each(data, function(i, v) {
// We need the v.
$("#master-dom").clone()
.removeAttr("id")
.find(".Name").text(v.name).end()
.find(".Age").text(v.age).end()
.appendTo("#content");
});
});
* {
margin: 0;
padding: 0;
list-style: none;
}
#master-dom {
display: none;
}
.item p strong {
display: inline-block;
width: 75px;
}
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<div id="master-dom" class="item">
<p><strong>Name</strong> <span class="Name"></span></p>
<p><strong>Age</strong> <span class="Age"></span></p>
</div>
<div id="content"></div>
I really believe this would be the underlying logic behind Angular's ng-repeat. Also I would use this above logic if I were in your place.
You could use ES6 feature Template literals
Your string would look like this
var newItem =
`<div class='item'>
<div class='item--poster'>
<img src='${data[key].backdropUrl}' alt='title'/>
</div>
<div class='item--content'>
<h2>${data[key].title}</h2>
<ul>
<li>${data[key].productionYear}</li>
<li>${data[key].productionCountry}</li>
</ul>
</div>
<div class='item--link'>
<p>
<a class='' href='${articleUrl}'>Lue lisää</a>
</p>
</div>
</div>`;