Understand first for result Angular2 ngFor - arrays

I have an array multidimensional with multiples results:
books: any[] = [
{
name: "The Name book",
chapter: [{
name: 'Alpha',
pages: '180'
}, {
name: 'Beta',
pages: '100'
}]
},
{
name: "Jungle Book",
chapter: [{
name: 'Whole book',
pages: '300'
}]
}
]
I would like to understand how to create a *ngIf when a book has just one chapter like "Jungle book" or multiples as "The Name Book."
Thanks for your help

I am not sure I have fully understood the selection creteria.
Anyway, assuming the template where you want to add the *ngIf check is defined in the same Component where you define the books property, I would try something like this
In the template
<div *ngFor="let book of books">
<div *ngIf="isBookToShow(book)">
<!-- here goes the rest of your html -->
</div>
</div>
with the corresponding method isBookToShow(book) in the class
isBookToShow(book) {
return book.chapter.length > 0
}

Related

How to show a dynamic list in the email body using mailjet

I'm using mailjet to send emails in my website. The emails sent include variables e.g name, email address, phone no...etc. I'm using template literals to include the variables and it is working fine when it is just one variable, but when I want to map over an array it shows [object Object] for every element instead of showing the actual variable.
How do I achieve iterating an array?
I was using the normal jsx syntax.
Here is part of the code:
const request = await mailjet
.post('send', {
version: 'v3.1'
})
.request({
Messages: [{
From: {
Email: "email#gmail.com",
Name: "Pilot"
},
To: [{
Email: "anotheremail#gmail.com",
Name: "Brian"
}],
Subject: "My first email!",
TextPart: "This is the text part",
HTMLPart: `<h3>Order from website</h3>
<p>Hi, I would like to order the following: </p>
<ul>
${cartItems.map(cartItem => (
<li key={cartItem._id}>{cartItem.name} {cartItem.quantity}kgs</li>
))}
</ul>
<p>Here are my contact details:</p>
<p>Name: ${firstName} ${lastName}</p>
<p>Email: ${email}</p>
<p>Mobile: ${mobile}</p>`,
TemplateLanguage: true
}]
});
This is how the cartItems look like:
[{ id: 1, name: 'Orange', quantity: 2 },{ id: 2, name: 'Pineapple', quantity: 9 }];

Why Angular ngFor does not check if the iterable object existing?

I am complete new to Angular 2. My understanding of Angular 2 is that it is based on TypeScript which compiles the source code to Javascript. As a compile language, I would expect it is able to catch any undefined variable, but it seems that it is not the case for ngFor. For example, in the following code (I am using VS Code), ngFor is used for iterate object heroes, it does not give me any error if heroes is not defined (when I defined heroes, I got a typo and defined it as heros, last second line):
import { Component } from '#angular/core';
*export class Hero {
id: number;
name: string;
}
const HEROES: Hero[] = [
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
];
#Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes" >
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
`
})
export class AppComponent {
name = 'Angular';
title = 'Tour of Heroes';
heros = HEROES;
}*
Could somebody kindly explain to me why? Do I expect too much?
If the property referenced by *ngFor to iterate over is null or undefined, *ngFor just doesn't do anything. You won't get an error for this.
TypeScript is a superset of JavaScript and undefined is a perfectly valid value for a property in JS and TS.
Angular2 for Dart however produces an error for such cases.

How can I populate a SELECT in a data grid?

I have this object:
phraseFormId = [
{
id: 1,
name: 'Word'
}, {
id: 2,
name: 'Sentence'
}
];
What I would like to do is to change this read only row.formId to be a SELECT element where it will display and where I can choose new values:
<div>
<div>{{ row.formId}}</div>
</div>
Can anyone give me some ideas how I can do this?
Thanks
Certainly not sure, what exactly you are looking for but have a look on this fiddle, simple enough to start with. Let me know, if your problem statement is different.
Using
ng-repeat
Fiddle: http://jsfiddle.net/U3pVM/26336/
It is a little unclear exactly what you are asking for, but I think I may have found a solution.
Here is a DEMO
Let me know if this is what you were looking for!
It utilizes ng-options with select to create a dropdown with values that will bind to a model property
Html
<div ng-repeat="item in phraseFormId">
<h4 ng-bind="'Item ' + $index"></h4>
id: {{item.id}}<br>
name: {{item.name}}<br>
formId:
<select ng-model="item.formId" ng-options="id for id in formIds"></select>
</div>
Controller
$scope.formIds = [1,2,3];
$scope.phraseFormId = [
{
id: 1,
formId: 1,
name: 'Word'
}, {
id: 2,
formId: 2,
name: 'Sentence'
},
{
id: 3,
formId: 1,
name: 'Paragraph'
}, {
id: 4,
formId: 3,
name: 'Sentence'
}
];

How do you show ng-repeated children of filtered array?

I have a drop-down filtered array, but the array I'd like to use is a little more complex, with nested data, similar to this http://jsfiddle.net/vojtajina/u75us/
I'd like to combine both ideas, but can't figure out why my fiddle doesn't display the 'child nodes'
<div class="col-md-12" ng-controller="App04Ctrl">
<p>Search:
Filter:
<select ng-model="filterItem.store" ng-options="item.name for item in filterOptions.stores">
</select>
Sort:
<select ng-model="sortItem.store" ng-options="item.name for item in sortOptions.stores">
</select>
</p>
<ul>
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter" >Name: {{item.name}} Price: {{item.price}} Location: {{item.location}}</li>
<ul>
<li ng-repeat="package in location.packages">{{package.name}} has services:
<ul>
<li ng-repeat="service in package.services">{{service.name}}</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
angular.js:
var app = angular.module('app04', []);
function App04Ctrl($scope) {
//Contains the filter options
$scope.filterOptions = {
stores: [
{id : 2, name : 'Show All', location: 'All Locations' },
{id : 3, name : 'Ashburn', location: 'Ashburn' },
{id : 4, name : 'San Francisco', location: 'San Francisco' },
{id : 5, name : 'Denver', location: 'Denver' },
{id : 6, name : 'Chicago', location: 'Chicago' },
{id : 7, name : 'Irvine', location: 'Irvine' }
]
};
//Contains the sorting options
$scope.sortOptions = {
stores: [
{id : 1, name : 'Price Highest to Lowest' },
{id : 2, name : 'Price Lowest to Highest' },
]
};
//Mapped to the model to filter
$scope.filterItem = {
store: $scope.filterOptions.stores[0]
}
//Mapped to the model to sort
$scope.sortItem = {
store: $scope.sortOptions.stores[0]
};
//Watch the sorting model - when it changes, change the
//ordering of the sort (descending / ascending)
$scope.$watch('sortItem', function () {
console.log($scope.sortItem);
if ($scope.sortItem.store.id === 1) {
$scope.reverse = true;
} else {
$scope.reverse = false;
}
}, true);
//Custom filter - filter based on the location selected
$scope.customFilter = function (locations) {
if (locations.location === $scope.filterItem.store.location) {
return true;
} else if ($scope.filterItem.store.location === 'All Locations') {
return true;
} else {
return false;
}
};
// Location data
$scope.locations = [{
name: "product1",
price: 198,
location: 'Ashburn',
packages: [{
name: 'Doom Patrol',
services: [{
name: 'Mento'}, {
name: 'Vox'}, {
name: 'Robotman'}]}, {
name: 'Suicide Squad',
services: [{
name: 'King Shark'}]}, {
name: 'Shadowpact',
services: [{
name: 'Zauriel'}, {
name: 'Enchantress'}, {
name: 'Ragman'}, {
name: 'Nightshade'}]}]}, {
name: "product2",
price: 402,
location: 'Chicago',
packages: [{
name: 'Metal Men'}, {
name: 'Legion of Superheroes',
services: [{
name: 'Ultra Boy'}, {
name: 'Kid Quantum'}]}]}, {
name: "product2",
price: 300,
location: 'Denver',
packages: [{
name: 'Freedom Fighters',
services: [{
name: 'Damage'}, {
name: 'Iron Munro'}]}, {
name: 'Birds of Prey',
services: [{
name: 'Huntress'}, {
name: 'Black Alice'}]}]}, {
name: "product2",
price: 1243,
location: 'Irvine',
packages: [{
name: 'The Outsiders'}, {
name: 'Zoo Crew',
services: [{
name: 'Rubberduck'}, {
name: 'Captain Carrot'}]}, {
name: 'The Elite',
services: [{
name: 'Vera Black'}, {
name: 'Manchester Black'}]}, {
name: 'Justice Legion Alpha'}]}
];
}
http://jsfiddle.net/jdacio/Vfx3y/2/
What am I missing? Am I on the right track? is there a better way to do this?
There are two problems that I see in your code above:
[1] Notice that you have closed the <li> tag, thus stopping the nesting of your ng-repeat directive to show the packages and and services of each item location. Simply remove the </li> closing tag and that should solve your first problem.
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter" >
Name: {{item.name}}
Price: {{item.price}}
Location: {{item.location}}
</li> <!-- THIS IS THE PROBLEM!! -->
[2] As what Mosho mentioned, your nested ng-repeat directive is using a location reference which does not exist in the current context of its parent ng-repeat directive. The simplest solution would be to change
<li ng-repeat="package in location.packages">
to
<li ng-repeat="package in item.packages">
The resulting HTML code should be:
<ul>
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter" >
Name: {{item.name}}
Price: {{item.price}}
Location: {{item.location}}
<ul>
<li ng-repeat="package in location.packages">{{package.name}} has services:
<ul>
<li ng-repeat="service in package.services">{{service.name}}</li>
</ul>
</li>
</ul>
</li>
</ul>
Instead of location.packages, it should be item.packages. (or 'location in locations' rather than 'item in locations').
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter">
...
<li ng-repeat="package in location.packages">
You refer to location, but you declare item in locations.

Select in AngularJS

I am trying to show a select box inside a ng-repeat and am stuck with the following:
<tr ng-repeat="element in elements" post-repeat-directive>
<td>{{element.name}}</td>
<td>
<select ng-model="element.type"
ng-options="item.id as item.name for item in tipo_items"></select>
</select>
</td>
</tr>
In my controller I have:
$scope.tipo_items = [
{ id: 1, name: 'uno' },
{ id: 2, name: 'dos' },
{ id: 3, name: 'tres' },
{ id: 4, name: 'cuatro' },
{ id: 5, name: 'cinco' },
];
This shows the select items, but no item is pre-selected!
I checked the element.type values and they are correct...
What am I doing wrong?
According to the comprehension expression you defined in the select, you need to use the id value to preselect the item and set it for the model object.
$scope.element = {};
$scope.element.type = $scope.tipo_items[0].id;
DEMO
OK I found the problem...
I was loading the id from the database as json, and the id was a string, not an integer...
this solved the problem:
$scope.tipo_items = [
{ id: '1', name: 'uno' },
...
instead of
$scope.tipo_items = [
{ id: 1, name: 'uno' },
...
This is default behavior by angular select directive. If you'll set ng-model to a default in the ctrl you'll get it preselected.
something like (in the ctrl):
$scope.element.name = $scope.tipo_items[0]

Resources