How can I render two object in div? - javascript

I have 2 objects with data and I need to restruct the rendering in html.
This is what I get:
but this is what I need to obtain:
Black box is the *ngFor of articles object, respectively red one is *ngFor of adsContainer object
<div *ngFor="let article of articles; let i = index;">
<mat-card class="card">
<div>
<a class="title">
{{article.title}}
</a>
<a>
<p>{{article.content}}</p>
</a>
</div>
</mat-card>
<div class="container" *ngIf="(i % 7) === 6">
<div *ngFor="let data of adsContainer">
<div>
<h1>{{data.value}}</h1>
</div>
</div>
</div>
</div>
public adsContainer: any = [
{ id: '1', value: 'text value here' },
{ id: '2', value: 'text value here' },
{ id: '3', value: 'text value here' }
]
public articles: any = [
{ id: '1', title: 'title value here', content: 'content here' },
{ id: '2', title: 'title value here', content: 'content here' },
{ id: '3', title: 'title value here', content: 'content here' },
........
{ id: '20', title: 'title value here', content: 'content here' },
]

Your issue is that you add your ads containers in a loop
<div class="container" *ngIf="(i % 7) === 6">
<!-- this loop here -->
<div *ngFor="let data of adsContainer">
<div>
<h1>{{data.value}}</h1>
</div>
</div>
</div>
what you want is to add only one ad container at a time, in order to do that, you have to rmove the loop
In order to have the three ads show, you'll have to do some math to get the ad index from the article index
something like this :
<div class="container" *ngIf="(i % 7) === 6">
<div>
<h1>{{adsContainer[mathFloor(i / 7)].value}}</h1>
</div>
</div>
note that Math is not available in angular templates, you'll have to redefine floor as a component method
function mathFloor(val) {return Math.floor(val)}

Try to use directly the array , also when you call
adsContainer[(parseInt(i / 6)-1)% adsContainer.length, it will always restart the index:
<div *ngFor="let article of articles; let i = index;">
<mat-card class="card">
<div>
<a class="title">
{{article.title}}
</a>
<a>
<p>{{article.content}}</p>
</a>
</div>
</mat-card>
<div class="container" *ngIf="(i % 7) === 6">
<div>
<div>
<h1>{{adsContainer[(parseInt(i / 6)-1)%adsContainer.length].value}}</h1>
</div>
</div>
</div>
</div>

Related

Javascript - loop to create list of cards

HTML and simple JS (no react / vue).
I need to do a list of cards and would like to do a loop to avoid repeating the html.
My current code :
<div id="products-cards-container">
<div class="products-cards">
<div class="product-header">
<img src="../assets/img/image1.png"/>
</div>
<div class="product-content">
<h4>title 1</h4>
<p>super content 1</p>
</div>
<button class="info-button">+ info</button>
</div>
<div>
<div class="product-header">
<img src="../assets/img/cards/products/image2.png"/>
</div>
<div class="product-content">
<h4>title 2</h4>
<p>super content 2</p>
</div>
<button class="info-button">+ info</button>
</div>
<div>
<div class="product-header">
<img src="../assets/img/cards/products/image-3.png"/>
</div>
<div class="product-content">
<h4>title 3</h4>
<p>blablablablbalbalbabla blablaba</p>
</div>
<button class="info-button">+ info</button>
</div>\
</div>
I am trying to return html
script.js
const valuesCards = [
{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
]
creating a function that inserts the list of cards in the .products-cards div :
function returnCards() => {
----- AND HERE I AM STUCK
(as well, all tries I did with a simple array / object returned only the last info) ----
}
Use Array.prototype.map function and a template literal.
const container = document.getElementById('products-cards-container');
const valuesCards = [{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
]
function returnCards(valuesCards) {
return "<div class=\"products-cards\">" + valuesCards.map(valuesCard => `
<div>
<div class="product-header">
<img src="${valuesCard.image}"/>
</div>
<div class="product-content">
<h4>${valuesCard.title}</h4>
<p>${valuesCard.content}</p>
</div>
<button class="info-button">+ info</button>
</div>`).join('') + "</div>";
}
container.innerHTML = returnCards(valuesCards);
<div id="products-cards-container"></div>
You can do it this way
const valuesCards = [
{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
];
let cardHTML = '';
valuesCards.map(element => {
cardHTML += '<div> \
<div class="product-header"> \
<img src="'+element.image+'"/> \
</div> \
<div class="product-content"> \
<h4>'+element.title+'</h4> \
<p>'+element.content+'</p> \
</div> \
<button class="info-button">+ info</button> \
</div> \
';
});
document.getElementsByClassName('products-cards')[0].innerHTML = cardHTML;
<div id="products-cards-container">
<div class="products-cards">
</div>
</div>
const valuesCards = [
{
image: '../img/image1.png',
title: 'title 1',
content: 'super content 1',
},
{
image: '../img/image2.png',
title: 'title 2',
content: 'super content 2'
},
{
image: '../img/image-3.png',
title: 'title3',
content: 'blablablablbalbalbabla blablaba'
},
]
valuesCards.map(card=> {
var cardDiv = document.createElement('div');
cardDiv.innerHTML = `
<div class="product-header">
<img src="${card.image}"/>
</div>
<div class="product-content">
<h4>${card.title}</h4>
<p>${card.content}</p>
</div>
<button class="info-button">+ info</button>`
document.getElementsByClassName('products-cards')[0].appendChild(cardDiv);
})
<div id="products-cards-container">
<div class="products-cards">
</div>
</div>
You need to do a "for loop" that iterates over your valuesCards object and for each value return an html template an inject into the desired element in DOM.
For example:
// Define the object
const valuesCards = [
{
'image': '../img/image1.png',
'title': 'title 1',
'content': 'super content 1',
},
{
'image': '../img/image2.png',
'title': 'title 2',
'content': 'super content 2'
},
{
'image': '../img/image-3.png',
'title': 'title3',
'content': 'blablablablbalbalbabla blablaba'
}
]
// Identify the DOM element to store cards
cardsContainer = document.querySelector('#products-cards-container');
// Create a loop that iterates over valuesCards object
for (let value of Object.values(valuesCards)) {
console.log(value.title);
// Create an element to store new card content
let newCard = document.createElement('DIV');
// Add products-cards class to new element
newCard.classList.add('products-cards');
// Create a multiline string template with current values each time
cardHtml = `
<div class="">
<div class="product-header">
<img src="${value.image}"/>
</div>
<div class="product-content">
<h4>${value.title}</h4>
<p>${value.content}</p>
</div>
<button class="info-button">+ info</button>
</div>
`;
// Append the new element to the cardsContainer element in DOM
cardsContainer.appendChild(newCard);
// Inject the template html on DOM's new append item
newCard.innerHTML = cardHtml;
}
Important!! create a div element with the id="products-cards-container" in the html where you want to print the cards.

Vue how to traverse the list correctly?

I just writed the vue simple code, But unable to follow the HTML effect. After traversal rendering a bit wrong. If gift object is no, for example the goods object has two data, goods_b1 + goods_b2. But i want to follow the HTML effect. Go to the HTML still. And go to the vue loops.
I want to the this effect:
Look at the javascript:
var app = new Vue({
el: "#app",
data: {
list: [{
id: 1,
name: 'A',
goods: [{
name: "goods_a1"
}],
gift: [{
name: "gift_a1",
}]
}, {
id: 2,
name: 'B',
gift: [],
goods: [{
name: "goods_b1"
}, {
name: "goods_b2"
}],
}, {
id: 3,
name: 'C',
goods: [{
name: "goods_c1"
}, {
name: "goods_c2"
}, {
name: "goods_c3"
}],
gift: [{
name: "gift_c1",
}]
}]
}
})
HTML:
<div id="app">
<div class="mui-row" v-for="item in list">
<div class="span-title-main">
<span class="span-title">{{item.name}}</span>
</div>
<br>
<ul>
<li>
<div class="mui-col" v-for="items in item.goods">
<span class="span-name">{{items.name}}</span>
</div>
<div class="addspan">+</div>
<div class="mui-col" v-for="itemss in item.gift">
<span class="span-name">{{itemss.name}}</span>
</div>
<div class="addspan">+</div>
</li>
</ul>
</div>
</div>
Are you asking that the (+) being inside the loop of your goods and gift ?
<div id="app">
<div class="mui-row" v-for="item in list">
<div class="span-title-main">
<span class="span-title">{{item.name}}</span>
</div>
<br>
<ul>
<li>
<div class="mui-col" v-for="items in item.goods">
<span class="span-name">{{items.name}}</span>
<div class="addspan">+</div>
</div>
<div class="mui-col" v-for="itemss in item.gift">
<span class="span-name">{{itemss.name}}</span>
</div>
</li>
</ul>
</div>
</div>
Edit: Remove the (+) for gifts loop as requested by OP.
Note: if the OP is asking to have a style for element in between goods and gift. I would suggest to use the css :last selector with a display:none to have this kind of effect.
It looks like the only difference is that you want a + button to appear after each item.goods instead of just one after the loop.
So put it inside the loop:
<template v-for="items in item.goods"><!-- using "template" to avoid modifying your html structure; you could of course use any tag -->
<div class="mui-col">
<span class="span-name">{{items.name}}</span>
</div>
<div class="addspan">+</div>
</template>
<div class="mui-col" v-for="items in item.gift">
<span class="span-name">{{items.name}}</span>
</div>
<!-- your image doesn't show a + button after gifts, so I've omitted it here -->

Angularjs change text according to true false status

I am making a box with ng-repeat here is the html
<div class="mission_box clearfix" ng-repeat="mission in missions">
<img src="images/tick_patch.png" class="expired_img">
<h2>{{mission.name}}</h2>
<p class="clearfix"><em>Win</em> <span><img src="images/crown.png"> {{mission.crownwin}} Crowns</span> <span><img src="images/voucher.png"> {{mission.voucherwin}} Voucher</span></p>
<div class="progress_box_outer clearfix">
<div class="progress_box">
<span style="width:{{100/mission.tasktotal*mission.taskdone}}%"></span>
</div>
<p class="progress_count">{{mission.taskdone}}/{{mission.tasktotal}}</p>
</div>
<div class="expiry_date">
<p>{{mission.expiry | missionexpire}}</p>
</div>
</div>
And here is the defined array in controller for this
$scope.missions = [
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'3','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true},
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'2','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true}
]
And filter i have created yet
.filter('missionexpire', function(){
return function(input){
if(input == true){
input = 'Completed'
} else {
input = input
}
}
})
In the above code you can see the last div in html with class .expiry_date i have defined filter in that.
What exactly i want is to change the text of {{mission.expiry}} if the status of {{mission.iscomplete}} is true.
Any help is appreciated. Thanks.
You could simply achieve this without a filter. Just use a conditional expression like
<p>{{mission.iscompleted === true?'Completed': mission.expiry}}</p>
angular.module('app', []).controller('AppController', function($scope) {
$scope.missions = [{
'name': '3 Start Checkins',
'crownwin': '100',
'voucherwin': 'flipkart',
'tasktotal': '4',
'taskdone': '3',
'expiry': 'Expire on 25/06',
'isExpired': false,
'iscompleted': true
}, {
'name': '3 Start Checkins',
'crownwin': '100',
'voucherwin': 'flipkart',
'tasktotal': '4',
'taskdone': '2',
'expiry': 'Expire on 25/06',
'isExpired': true,
'iscompleted': false
}, {
'name': '3 Start Checkins',
'crownwin': '100',
'voucherwin': 'flipkart',
'tasktotal': '4',
'taskdone': '2',
'expiry': 'Expire on 25/06',
'isExpired': false,
'iscompleted': false
}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="AppController">
<div class="mission_box clearfix" ng-repeat="mission in missions">
<h2>{{mission.name}}</h2>
<p class="clearfix"><em>Win</em> <span>{{mission.crownwin}} Crowns</span> <span> {{mission.voucherwin}} Voucher</span>
</p>
<div class="progress_box_outer clearfix">
<div class="progress_box">
<span style="width:{{100/mission.tasktotal*mission.taskdone}}%"></span>
</div>
<p class="progress_count">{{mission.taskdone}}/{{mission.tasktotal}}</p>
</div>
<div class="expiry_date">
<p>{{mission.iscompleted === true?'Completed': (mission.isExpired === true ? 'Expired' : mission.expiry)}}</p>
</div>
</div>
</div>
</body>
If you want to achieve this by filter try this. From the filter you need to return anything.
.filter('missionexpire', function(){
return function(input, iscompleted){
if(iscompleted){
return 'Completed';
} else {
return input;
}
}
})
and
<div class="expiry_date">
<p>{{mission.expiry | missionexpire:misson.iscompleted}}</p>
</div>
var app = angular.module('myApp', []);
app.controller('MyCtrl',['$scope', function($scope){
$scope.missions = [
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'3','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true},
{'name':'3 Start Checkins', 'crownwin':'100', 'voucherwin':'flipkart','tasktotal':'4','taskdone':'2','expiry':'Expire on 25/06','isexpired':false,'iscompleted':true}
]
}])
app.filter('missionexpire', function(){
return function(input, isCompleted){
if(isCompleted){
return 'Completed';
} else {
return input;
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='myApp' ng-controller='MyCtrl'>
<div class="mission_box clearfix" ng-repeat="mission in missions">
<h2>{{mission.name}}</h2>
<p class="clearfix"><em>Win</em> <span>{{mission.crownwin}} Crowns</span> <span> {{mission.voucherwin}} Voucher</span>
</p>
<div class="progress_box_outer clearfix">
<div class="progress_box">
<span style="width:{{100/mission.tasktotal*mission.taskdone}}%"></span>
</div>
<p class="progress_count">{{mission.taskdone}}/{{mission.tasktotal}}</p>
</div>
<div class="expiry_date">
<p>{{mission.expiry | missionexpire:mission.iscompleted}}</p>
</div>
</div>
</div>
To filter content according to a specific property value in AngularJs there are used Pipes ( | )
So, in your section:
<div class="expiry_date">
<p>{{mission.expiry | missionexpire}}</p>
</div>
You add only the property but not the evaluation for that property. To do so you need to change that to,
<div class="expiry_date">
<p>{{mission.expiry | missionexpire:iscomplete}}</p>
</div>

How can I repeat through objects on click or swipe using angularjs?

I have a list of object element like:
$scope.products = [
{
name: 'First News Heading',
content: 'Lorem ipsum',
cover: 'img/img1.jpg'
},
{
name: 'Second News Heading',
content: 'The veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim.',
cover: 'img/img2.jpg'
},
];
And I want to display then like:
<div class="thumbnail">
<img ng-src="{{ product.cover }}">
<p class="title">{{ product.name }}</p>
<p class="content">{{ product.content }}</p>
</div>
using ng-repeat displays all of them together. but I want to use a click or swipe up to display next-next element.
Try the following :
<div class="thumbnail">
<img ng-src="{{product.cover}}">
<p class="title">{{product.name}}</p>
<p class="content">{{product.content}}</p>
</div>
<input type="button" ng-click="previous()" value="Previous" />
<input type="button" ng-click="next()" value="Next" />
JS:
$scope.currentPosition=0;
$scope.product=$scope.products[0]; //initialize the product var with first element
$scope.next=function(){
$scope.currentPosition++;
if($scope.currentPosition <$scope.products.length)
$scope.product=$scope.products[$scope.currentPosition];
else
$scope.curentPosition=$scope.products.length-1;
}
$scope.previous=function(){
$scope.currentPosition--;
if($scope.currentPosition >=0)
$scope.product=$scope.products[$scope.currentPosition];
else
$scope.curentPosition=0;
}

transparency.js nested plain values

I was wondering why the following doesn't work:
Coffeescript:
post =
title: 'Hello World',
post: 'Hi there it is me',
comments: [
name: 'John',
text: 'That rules'
,
name: 'Arnold',
text: 'Great post!',
tags: ['a', 'b', 'c']
]
directives =
tags:
tag:
text: (target) -> this.value
$('.container').render post, directives
Template:
<div class="container">
<h1 class="title"></h1>
<p class="post"></p>
<div class="comments">
<div class="comment">
<span class="name"></span>
<span class="text"></span>
<div class="tags">
<span class='tag'></span>
</div>
</div>
</div>
</div>
It doesn't render the nested plain tags, nor does it ever execute the directive function for them
Any ideas?
This is the correct set of directives:
directives =
comments:
tags:
tag:
text: (target) -> this.value
Directives don't cascade by skipping unmentioned top layers the way normal values do, so you had to include the comments layer.

Categories

Resources