Ng-repeat in Angular bind to HTML template in object {{ key.value }} - angularjs

I've got an object in a service I'm trying to represent in the page markup. Notably a description key in the object that stores the local address of an HTML file with the relevant description.
Here is the object I'm referencing:
service.content = [
{
id: 'bootstrap-grid',
title: 'The Complete Basics of the Bootstrap 3 Grid',
type: 'article',
date: 'February 28, 2015',
description: 'articles/partial/BootstrapGrid/description.html',
pathToHTML: 'articles/partial/BootstrapGrid/BootstrapGrid.html',
ratingArr: [],
updated: null,
},
{
id: 'HTMLConverter',
title: 'Blog-friendly HTML Converter',
type: 'resource',
date: 'March 6, 2015',
description: 'components/HTMLconverter/description.html',
pathToHTML: 'components/HTMLconverter/friendlyHTML.html',
ratingArr: [],
updated: null,
}
];
Here is the markup I'm trying to work with. See the comment to pinpoint problem.
<div class="global-container" ng-controller="HomeCtrl">
<h1>New Content</h1>
<span ng-repeat="post in posts">
<h1>
{{ post.title }}
</h1>
<div>
{{ post.date }}
</div>
<div class="post-title">
<a ui-sref="post({ id: post.id })">
{{ post.title }}
</a>
</div>
<!-- How can I get this to display the contents of the local html file address at this location? -->
{{ post.description }}
<a ui-sref="post({ id: post.id })">
Read Article
</a>
</span>
</div>
I tried ng-include but to no avail.
<ng-include src={{ post.description }}></ng-include>
I also tried creating a directive, but template URL doesn't include the current the lexical scope. What are my options here?

Try
<ng-include src="post.description"></ng-include>

Related

Getting the collection name in AngularJS ngRepeat directive

If I have, for example, the array:
$scope.users = [
John: {
age: 18,
genre: 'male',
type: 'admin'
},
Paul: {
age: 22,
genre: 'male',
type: 'admin'
}
];
How can I get the users names when I iterate with ngRepeat?
<li ng-repeat="user in users">
{{ }} <!-- Name Here -->
{{ user.age }} <br>
{{ user.genre }} <br>
{{ user.type }}
</li>
Thanks!
1) You have error in your code: your array should be an object, since it has keys John, Paul ...
2) In ngRepeat you can iterate over object properties like (key, value) in obj
Here is working example:
angular.module('myApp', [])
.controller('MyCtrl', ['$scope', function MyCtrl($scope ) {
var ctrl = this;
ctrl.users = {
John: {
age: 18,
genre: 'male',
type: 'admin'
},
Paul: {
age: 22,
genre: 'male',
type: 'admin'
}
};
}]);
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.angularjs.org/1.6.2/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl as $ctrl">
<ul>
<li ng-repeat="(key, user) in $ctrl.users track by $index">
{{ key }}
{{ user.age }} <br>
{{ user.genre }} <br>
{{ user.type }}
</li>
</ul>
</div>
</div>
First of all arrays can't have custom keys. So I suppose you are using object $scope.users.
And for answer, you can do this: ng-repeat="(name, user) in users"
https://docs.angularjs.org/api/ng/directive/ngRepeat#iterating-over-object-properties
You can use Object.keys(users) to get an array with the values ['Paul','John']
<li ng-repeat="user in users track by $index">
{{ Object.keys(users)[$index] }}
{{ user.age }} <br>
{{ user.genre }} <br>
{{ user.type }}
</li>
this isn't tested but I think it should be along the lines of what you need.

Angular one-time binding on object keys? One-time add like button

Goal: Like button only adds once using Angular.
Theory: Angular's one-time binding will do the trick.
It works here on Angular Expression Doc and on the Plunker example
Problem: Doesn't work in my trials.
Here's the Controller info (from Codecademy's Book App exercise)
$scope.products = [
{
name: 'The Book of Trees',
price: 19,
pubdate: new Date('2014', '03', '08'),
cover: 'img/the-book-of-trees.jpg',
likes: 0,
dislikes: 0
},
{
name: 'Program or be Programmed',
price: 8,
pubdate: new Date('2013', '08', '01'),
cover: 'img/program-or-be-programmed.jpg',
likes: 0,
dislikes: 0
}
View Trial 1
<div ng-repeat="product in products" class="col-md-6">
<div class="thumbnail">
<img ng-src="{{ product.cover }}">
<p class="title">{{ product.name }}</p>
<p class="price">{{ product.price | currency }}</p>
<p class="date">{{ product.pubdate | date }}</p>
<div class="rating">
<p class="likes" ng-click="plusOne($index)">+ {{ ::product.likes}} </p> <!-- here's the damn pickle of a problem -->
<p class="dislikes" ng-click="minusOne($index)">+ {{ product.dislikes }} </p>
</div>
</div>
</div>
RESULT - The button doesn't add
View Trial 2
<div ng-repeat="product in products" class="col-md-6">
<div class="thumbnail">
<img ng-src="{{ product.cover }}">
<p class="title">{{ product.name }}</p>
<p class="price">{{ product.price | currency }}</p>
<p class="date">{{ product.pubdate | date }}</p>
<div class="rating">
<p class="likes" ng-click="plusOne($index)">+ {{ ::product.::likes}} </p> <!-- here's the damn pickle of a problem -->
<p class="dislikes" ng-click="minusOne($index)">+ {{ product.dislikes }} </p>
</div>
</div>
</div>
RESULT - No content shows, only Handlebars / Mustaches / Handlebar-Mustaches {{ }}
I tried implementing your code. The following works for me:
<div ng-repeat = 'product in products'>
<p ng-click="plusOne($index)"> + {{ product.likes}}</p>
<p ng-click="minusOne($index)"> + {{ product.dislikes }}</p>
</div>
Since products is an array, we need to iterate through each of its elements.
$scope.products = [
{
name: 'The Book of Trees',
price: 19,
pubdate: new Date('2014', '03', '08'),
cover: 'img/the-book-of-trees.jpg',
likes: 0,
dislikes: 0
},
{
name: 'Program or be Programmed',
price: 8,
pubdate: new Date('2013', '08', '01'),
cover: 'img/program-or-be-programmed.jpg',
likes: 0,
dislikes: 0
}];
$scope.plusOne = function(index){
if($scope.products[index].likes == 0){
$scope.products[index].likes++;
}
};
I am incrementing the value of likes only if it is 0. Hence it will get incremented only once.
Here's the quick error I see on your code. 1. remove the double colon (::) and change your + sign to -. See screenshot below:
https://i.gyazo.com/ae9d8bb8be57a7b9e9cf840d3f1d705b.png
Also, don't forget to attach your plus and minus properties on your scope(in your controller).
$scope.plusOne = function(index) {
$scope.products[index].likes += 1;
};
$scope.minusOne = function(index) {
$scope.products[index].dislikes += 1;
};
If I understand you correctly, you want the user to only be able to "like" or "dislike" a product once.
One-time binding is used to have the view only watch a value until it is defined, and then stop watching it. The main purpose it to not add extra watches when you are binding data that won't be changing to your view.
In the case of ng-click, the expression is not watched using a $watch, but rather, re-evaluated every time the button is clicked. Even if it worked with one-time and the expression was only evaluated once, that expression would still be used every time the button clicked.
You need to be tracking whether the user has already "liked" a product or not. You can then check that in your plusOne and minusOne functions, and simply short-circuit them if they've already been fired.
Alternately, you could simply have plusOne and minusOne simply replace themselves with empty functions after they fire, like so:
$scope.plusOne = function(index) {
// Do stuff...
// This function disables itself after it fires once
$scope.plusOne = function() {};
};

ng-model into ui-gmap-marker

I need help to use ng-model directive with ui-gmap-marker. My example app.js is:
// DevicesController
$scope.devices = {
id: 1,
center: { latitude: X, longitude Y },
options: {
show: true,
name: 'device 1',
radius: 100
}
(...)
}
My index.html is:
<ul ng-controller="DevicesController">
<li ng-repeat="d in devices">
<input type="checkbox" ng-model="d.options.show">
<span>{{ d.options.name }}</span>
</li>
</ul>
(...)
<div id="map_canvas" ng-controller="DevicesController">
<ui-gmap-marker
ng-repeat="d in devicesMarkers track by d.id"
idkey="d.id"
coords="d.center"
ng-model="d.options.show">
</ui-gmap-marker>
(...)
How can I use ng-model? Doesn't work because I'm using the same controller e two different places? I want that the user be able to click in input checkbox and the marker appear/disappear.
I'd suggest simply wrap both the div in same controller rather than providing a separate controller to them.
Markup
<div ng-controller="DevicesController">
<ul>
<li ng-repeat="d in devices">
<input type="checkbox" ng-model="d.options.show">
<span>{{ d.options.name }}</span>
</li>
</ul>
(...)
<div id="map_canvas">
<ui-gmap-marker
ng-repeat="d in devicesMarkers track by d.id"
idkey="d.id"
coords="d.center"
ng-model="d.options.show">
</ui-gmap-marker>
</div>
(...)
</div>
Else maintain the data in share able service that will provide the data to both controller and will make sure, data should be updated in both places.

AngularJS filter nested ng-repeat based on repeated object properties

I have an array of restaurant objects and I want to list them by grouping their cities
My object is like;
restaurant = {
id: 'id',
name: 'name',
city: 'city'
}
This HTML Markup can give some info about what I want to do.
<div ng-repeat="restaurant in restaurant | filter: ???">
<div class="header">
<h1 ng-bind="restaurant.city"></h1>
<a>Select All</a>
</div>
<div class="clearfix" ng-repeat="???">
<input type="checkbox" id="restaurant.id" />
<label ng-bind="restaurant.name"></label>
</div>
</div>
Can I do it with one single array or do i need to create seperate city and restaurant arrays to do it?
If you want to group restaurants by city, you can use groupBy of angular.filter module.
Just add the JS file from here: http://www.cdnjs.com/libraries/angular-filter to your project and use following code.
var myApp = angular.module('myApp',['angular.filter']);
function MyCtrl($scope) {
$scope.restaurants = [
{id: 1, name: 'RestA', city: 'CityA'},
{id: 2, name: 'RestB', city: 'CityA'},
{id: 3, name: 'RestC', city: 'CityC'},
{id: 4, name: 'RestD', city: 'CityD'}
];
}
<div ng-controller="MyCtrl">
<ul ng-repeat="(key, value) in restaurants | groupBy: 'city'">
<b>{{ key }}</b>
<li ng-repeat="restaurant in value">
<i>restaurant: {{ restaurant.name }} </i>
</li>
</ul>
</div>
I've created JSFiddle for you with working example.

How to handle selected/unselected ng-class to manage a tabbed popover

My code is as follows (the fiddle):
<div ng-controller="myCtrl">
<div ng-model="currentTab" ng-init="currentTab='Tab1'"/>
<div ng-init="popovers = [
{ name: 'Popover1',
displayName: 'Pop over with two tabs',
tabs: [
{ name: 'Tab1',
displayName: 'First tab',
description: ['First tab description']
},
{ name: 'Tab2',
displayName: 'Second tab',
description: ['Second tab description']
}
]
}
]"/>
<b>Tabs in popover</b>
<div
class="popover"
ng-repeat="p in popovers"
>
Popover name: {{p.displayName}}
<div ng-repeat="t in p.tabs"
class="tab"
ng-class="currentTab==t.name?'selected':''"
ng-click="currentTab=t.name"
>
{{t.name}}
</div>
<div ng-repeat="t in p.tabs"
class="tabContent"
ng-class="currentTab==t.name?'selected':''"
>
<p>{{t.displayName}}</p>
</div>
</div>
</div>
There is something I don't get which make the code not working perfectly, as the selected class name is never removed as one click on the tab.
When you want to modify a variable of your parent scope from within a ng-repeat you need to use $parent.currentTab.
Updated Fiddle

Resources