I'm not exactly sure how to describe the issue I am having, or even if it is an issue. I guess I am having trouble wrapping my head around how Angular Directives work. Any advice and/or opinion on best practice is welcomed.
I have a simple array of objects in my controller's $scope:
$scope.birthdays = [
{ name: "bob", dob:moment("09/20/1953"), cake: "vanilla"},
{ name: "michael", dob:moment("09/20/1953"), cake: "chocolate" },
{ name: "dave", dob:moment("09/20/1953"), cake: "chocolate" },
{ name: "chief", dob:moment("04/24/1977"), cake: "chocolate" },
{ name: "jerry", dob:moment("04/24/1977"), cake: "red velvet" },
{ name: "jerkface", dob:moment("04/24/1977"), cake: "i hate cake" },
{ name: "doug", dob:moment("05/10/1994"), cake: "marble" },
{ name: "jeff", dob:moment("05/10/1994"), cake: "vanilla" }
];
Say I would like to create a DOM structure from this data model:
<h1>Birthday: 09/20/1953</h1>
<div class="birthday">
<h2>Name: bob</h2>
<h3>Cake: vanilla</h3>
</div>
<div class="birthday">
<h2>Name: michael</h2>
<h3>Cake: chocolate</h3>
</div>
<div class="birthday">
<h2>Name: dave</h2>
<h3>Cake: chocolate</h3>
</div>
<h1>Birthday: 04/24/1977</h1>
<div class="birthday">
<h2>Name: chief</h2>
<h3>Cake: chocolate</h3>
</div>
....
I can achieve something close to this in this plunker.
There, however, I end up with a slightly different DOM structure that I don't want.
<div ng-repeat="birthday in birthdays" birthday-boy="">
<h3 ng-show="!birthdays[$index-1].dob.isSame(birthday.dob)" class="ng-binding" style="">
September 20th, 1953
</h3>
<div class="ng-binding">
Name: bob
</div>
<div class="ng-binding">
Cake: vanilla
</div>
</div>
<div ng-repeat="birthday in birthdays" birthday-boy="">
<h3 ng-show="!birthdays[$index-1].dob.isSame(birthday.dob)" class="ng-binding" style="display: none;">
September 20th, 1953
</h3>
<div class="ng-binding">
Name: michael
</div>
<div class="ng-binding">
Cake: chocolate
</div>
</div>
<div ng-repeat="birthday in birthdays" birthday-boy="">
<h3 ng-show="!birthdays[$index-1].dob.isSame(birthday.dob)" class="ng-binding" style="">
April 24th, 1977
</h3>
<div class="ng-binding">
Name: chief
</div>
<div class="ng-binding">
Cake: chocolate
</div>
</div>
So, my questions are:
Am I thinking about this problem correctly? Should I be modifying my data structure to group it by dates there, and then just ng-repeat over each individual date?
If there is a way to do this with my existing data structure, do I need to modify the DOM outside of the birthday-boy / ng-repeat directive?
Is there a way to wrap the ng-repeat directive into something custom - I have started looking into the compile function but, just not sure...
Thanks!
I would group by dates in your controller, then ng-repeat over that new scope property. Here is a fiddle I wrote for a similar "group by" question. You should be able to adapt it for your code. I used the orderByFilter
$scope.sortedFriends = orderByFilter($scope.friends, '+age');
but you'll likely need to use the dateFilter or whatever JavaScript code you might have around to sort by the dob stuff.
Related
My end result is supposed to be a list of objects in html. Bootstrap behind this. I'd like for the list to be created dynamically so I don't have to manually create all the divs because I don't know how many there will be. Here's what I have.
I have an array similar to this:
activities =
[
{
"activityOwner": "Raymond Carlson",
"activityDesc": "Complete all the steps from Getting Started wizard"
},
{
"activityOwner": "Flopsy McDoogal",
"activityDesc": "Called interested in March fundraising Sponsorship"
},
{
"activityOwner": "Gary Busy",
"activityDesc": "Get approval for price quote"
}
]
This is the first part where I'm not sure what to do. I can assign the element ids individually for my html like this but what I'd like to do is count how many elements are in my array and create these for me. I won't know how many there are to make these manually. I'm sure there needs to be a loop but I couldn't figure it out.
document.getElementById('activityowner0').innerHTML = activities[0].activityOwner;
document.getElementById('activitydesc0').innerHTML = activities[0].activityDesc;
document.getElementById('activityowner1').innerHTML = activities[1].activityOwner;
document.getElementById('activitydesc1').innerHTML = activities[1].activityDesc;
document.getElementById('activityowner2').innerHTML = activities[2].activityOwner;
document.getElementById('activitydesc2').innerHTML = activities[2].activityDesc;
etc.
etc.
And then...once I have that part, I'd like to know how to create my html divs dynamically based on how many elements are in my array. Again, right now I don't know how many there are so I'm having to create a bunch of these and then have extras if I have too many.
<div class="container">
<div class="row"></div>
<div class="qa-message-list" id="wallmessages">
<br>
<div class="message-item" id="m0">
<div class="message-inner">
<div class="message-head clearfix">
<div class="user-detail">
<h5 class="handle">
<p id='activityowner0'></p>
</h5>
<div class="post-meta"></div>
</div>
</div>
<div class="qa-message-content">
<p id='activitydesc0'></p>
</div>
</div>
</div>
I know this is a big ask so just pointing me in the right direction would be very helpful. I hope my question was clear and I appreciate it.
One way for you to achieve this would be to loop through the objects in your activities array. From there you can use a HTML template to store the base HTML structure which you can clone and update with the values of each object before you append it to the DOM.
In addition, an important thing to note when generating repeated content in a loop: never use id attributes. You will either end up with duplicates, which is invalid as id need to be unique, or you'll end up with ugly code generating incremental/random id at runtime which is unnecessary. Use classes instead.
Here's a working example:
const activities = [{ "activityOwner": "Raymond Carlson", "activityDesc": "Complete all the steps from Getting Started wizard"}, {"activityOwner": "Flopsy McDoogal","activityDesc": "Called interested in March fundraising Sponsorship" }, { "activityOwner": "Gary Busy", "activityDesc": "Get approval for price quote" }]
const html = activities.map(obj => {
let item = document.querySelector('#template').innerHTML;
item = item.replace('{owner}', obj.activityOwner);
item = item.replace('{desc}', obj.activityDesc);
return item;
});
document.querySelector('#list').innerHTML = html.join('');
<div id="list"></div>
<template id="template">
<div class="container">
<div class="row"></div>
<div class="qa-message-list">
<div class="message-item">
<div class="message-inner">
<div class="message-head clearfix">
<div class="user-detail">
<h5 class="handle">
<p class="activityowner">{owner}</p>
</h5>
<div class="post-meta"></div>
</div>
</div>
<div class="qa-message-content">
<p class="activitydesc">{desc}</p>
</div>
</div>
</div>
</div>
</div>
</template>
Hi i am making a books website and im trying to add a hyperlink using href but it comes up in the same line is there any way to make it to show in a different line?here is how it shows up right now
const petsData = [{
name: "Story Book",
species: "Jean Lumier",
favFoods: ["wet food", "dry food", "<strong>any</strong> food"],
birthYear: 2016,
href: "https://media.sproutsocial.com/uploads/2017/02/10x-featured-social-media-image-size.png",
photo: "https://nice-assets.s3-accelerate.amazonaws.com/smart_templates/e639b9513adc63d37ee4f577433b787b/assets/wn5u193mcjesm2ycxacaltq8jdu68kmu.jpg"
},
{
name: "Barksalot",
species: "Dog",
href:"https://www.amazon.in/Redmi-9A-2GB-32GB-Storage/dp/B08696XB4B/ref=gbph_img_m-2_0ec7_a9c5af13?smid=A23AODI1X2CEAE&pf_rd_p=cbec21a0-e969-48e2-8697-caf621220ec7&pf_rd_s=merchandised-search-2&pf_rd_t=101&pf_rd_i=1389401031&pf_rd_m=A1VBAL9TL5WCBF&pf_rd_r=7N08PRZ1WREYVED1R3Q4",
birthYear: 2008,
photo: "https://learnwebcode.github.io/json-example/images/dog-1.jpg"
},
{
name: "Meowsalot",
species: "Cat",
favFoods: ["tuna", "catnip", "celery"],
birthYear: 2012,
photo: "https://learnwebcode.github.io/json-example/images/cat-1.jpg"
}
];
//empty space thing (ㅤ)
function petTemplate(pet) {
return `
<div class ="image-grid">
<div class="animal">
<img class="pet-photo " src="${pet.photo}">
<div class="olay">
<h2 class="pet-name">${pet.name}
//href here
<h1 class="species">${pet.species}
<a href= ${pet.href}> Read Reviews</a>
<div></div></div>
</div>
</div>
`;
}
(Sorry english is not my main language)
There are several simple ways to achieve this:
Perhaps the easies it to wrap your link in a div
<div><a href= ${pet.href}> Read Reviews</a></div>
Another option is to have br tag before the link <a href= ${pet.href}> Read Reviews</a>
The most standard way to achieve your task might be to use flexbox in your CSS style read more about flexbox here https://www.w3schools.com/css/css3_flexbox.asp
Try this
<div class ="image-grid">
<div class="animal">
<img class="pet-photo " src="${pet.photo}">
<div class="olay">
<h2 class="pet-name">${pet.name} </h2>
//href here
<h1 class="species">${pet.species} </h1>
<a href= ${pet.href}> Read Reviews</a>
</div>
</div>
</div>
Or you can wrap h2, h1 and the a tag in its own div
You have to close your <h1> and <h2> tags (with </h1> and </h2>, not with </div>!)
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 -->
I'm desperate in trying to find a solution.
Here is my profile page structure:
private formSections: any[] = [
{title: 'General information', name: 'general'},
{title: 'Financial Information', name: 'financial'},
{title: 'Languages', name: 'languages'},
{title: 'Education', name: 'education'},
{title: 'Featured Skills', name: 'skills'},
{title: 'Certificates', name: 'certificates'},
{title: 'Experience', name: 'experience'},
...];
Each section should contain a different form with selects, inputs, datepickers, draggable items, chips etc. But in the same time it should be a one large form that will be published to the server.
Since it's a pretty big amount of form elements and they are separated visually in my layout, it would be wise to split them to components.
But I cannot find any examples online of how to achieve that.
Here is how my main component looks like:
// profile.component.html
<form [formGroup]="profileForm" novalidate (ngSubmit)="save(profileForm)">
<div id="{{section.name}}" *ngFor="let section of formSections">
<div class="editprofile-title">{{section.title}}</div>
<div class="editprofile-form" >
<div *ngIf="section.name=='general'"
[group]="profileForm"
profileGeneralFormComp ></div>
<div *ngIf="section.name=='financial'"
profileFinancialFormComp
[group]="profileForm"></div>
<div *ngIf="section.name=='languages'"
profileLanguagesFormComp
[group]="profileForm"></div>
<div *ngIf="section.name=='education'"
profileEducationFormComp
[group]="profileForm"></div>
<div *ngIf="section.name=='skills'"
profileSkillsFormComp
[group]="profileForm"></div>
<div *ngIf="section.name=='certificates'"
profileCertificatesFormComp
[group]="profileForm"></div>
<div *ngIf="section.name=='experience'"
profileExperienceFormComp
[group]="profileForm"></div>
<div *ngIf="section.name=='links'"
profileLinksFormComp
[group]="profileForm"></div>
</div>
</div>
</form>
Main struggle is that i can't pass a parent formGroup to my component and fill it with formControls inside.
Any help/advice will be appreciated.
So I'm trying to duplicate the section div (so I can have multiple sections with multiple articles). I tried using the same controller for both divs as shown below. So I'm able to add the section by appending it to main but I can't edit the second div. Is there any way around this?
I am not using bootstrap and i'm using xeditable.
HTML:
<div id="main" ng-app="main">
<div class = "section" ng-controller="newsController">
<h2 id="section" editable-text="sections.section">{{sections.section}}</h2>
<div class = "article" ng-repeat="article in sections.articles">
<h3 id="title" editable-text="article.title"><a editable-text="article.link" href="{{article.link}}">{{article.title}}</a></h3>
<p id="publisher" editable-text="article.publisher">{{article.publisher}}</p>
<p id="orig_title" editable-text="article.orig_title">{{article.orig_title}}</p>
<p id="descr" ng-bind-html="article.description" editable-text="article.description"></p>
</div>
<div class = "section" ng-controller="newsController">
</div>
</div>
JS:
newsletter.controller('newsController',function($scope){
$scope.sections = {
section: "Faculty",
articles: [
{
title: "In __ We Trust",
link:'http://wee.com',
publisher: "Me",
orig_title:"",
description: "Description Here"
}
]
};
$scope.addItem = function(){
$scope.sections.articles.push(this.sections.articles.temp);
$scope.sections.articles.temp={};
};
)};
var newSection = '//Pretend all the tags and the attributes as above are placed here'
$("#add-section").click(function(){
var $section = $('#main').append(newSection);
});
Apologies for formatting. I'm still new to this. Thanks!
Edit: I'm also trying to make this dynamic so the user could edit the texts like the title and the publisher, etc. How would I make the added section also editable?
Try it this way, instead of appending it uses angulars natural way of repeating divs aka ng-repeat:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.sections = {
section: "Faculty",
articles: [{
title: "In __ We Trust",
link: 'http://wee.com',
publisher: "Me",
orig_title: "",
description: "Description Here"
}]
};
$scope.addItem = function() {
$scope.sections.articles.push(this.sections.articles.temp);
$scope.sections.articles.temp = {};
};
var newSection = '//Pretend all the tags and the attributes as above are placed here'
$("#add-section").click(function() {
var $section = $('#main').append(newSection);
});
});
</script>
<div id="main" ng-app="myApp" ng-controller="myCtrl">
<div class="section" ng-repeat="i in ['0','1']">
<h2 id="section" editable-text="sections.section">{{sections.section}}</h2>
<div class="article" ng-repeat="article in sections.articles">
<h3 id="title" editable-text="article.title"><a editable-text="article.link" href="{{article.link}}">{{article.title}}</a></h3>
<p id="publisher" editable-text="article.publisher">{{article.publisher}}</p>
<p id="orig_title" editable-text="article.orig_title">{{article.orig_title}}</p>
<p id="descr" ng-bind-html="article.description" editable-text="article.description"></p>
</div>
<div class="section" ng-controller="myCtrl"></div>
</div>
I Got the answer! So I applied the app to the html document and the controller to the body as opposed to the main div and made an array of sections as opposed to a singular section. I did a ng-repeat for the section div. By doing so, I added a "addsection" function where I create a section to be added to the array and the section has to have the same properties as the other ones including an empty array of articles.
HTML:
<body ng-controller="newsController">
<ul id="convenient-buttons">
<li id="add-section">Add Section</li>
<li>Select All</li>
<li><a href=# id="export" onclick="selectText('json')" ng-mouseenter="showJson=true" ng-mouseleave="showJson=false" >Send to Server</a></li>
</ul>
<div id="main">
<div class = "section" ng-repeat="section in news.sections" >
<h2 id="section" editable-text="sections.section">{{sections.section}}</h2>
<div class = "article" ng-repeat="article in sections.articles">
<h3 id="title" editable-text="article.title"><a editable-text="article.link" href="{{article.link}}">{{article.title}}</a></h3>
<p id="publisher" editable-text="article.publisher">{{article.publisher}}</p>
<p id="orig_title" editable-text="article.orig_title">{{article.orig_title}}</p>
<p id="descr" ng-bind-html="article.description" editable-text="article.description"></p>
</div>
</div>
</body>
JS:
$scope.news = {
sections: [
{
title: "Faculty",
articles: [
{
title: "In Memoriam: Eli Pearce",
link:'http://engineering.nyu.edu/news/2015/05/29/memoriam-eli-pearce',
publisher: "NYU Newsroom",
orig_title:" ",
description: "When <strong>Professor Eli Pearce</strong> passed away on May 19, 2015, a slice of Poly history passed along with him. Pearce had been affiliated with the school, then known as the Polytechnic Institute of Brooklyn, since the mid-1950s, when he conducted his doctoral studies in chemistry here. As a student, he learned with such luminaries as Herman Frances Mark, who is often called the Father of Polymer Science, and Charles Overberger, another influential chemist who helped establish the study of polymers as a major sub-discipline."
}
]
}
]
};
$scope.addSection = function(){
$scope.news.sections.temp={
title: "Section Title",
articles:[
// {
// title:"Article Title",
// link:"Link",
// publisher: "Publisher",
// orig_title: "Original Title",
// description: "Description"
// }
]
};
$scope.news.sections.push(this.news.sections.temp);
};