Use local variable in template html without component Angular2+ - html

I want to use a local variable into my html template to use it in css classes but without linking it with the component. I want to do that :
[local_html_variable = 1]
<div class="css-{{ local_html_variable }}">
Div #1
</div>
[local_html_variable + 1]
<div class="css-{{ local_html_variable }}">
Div #2
</div>
[local_html_variable + 1]
<div class="css-{{ local_html_variable }}">
Div #3
</div>
...
to get
<div class="css-1">
Div #1
</div>
<div class="css-2">
Div #2
</div>
<div class="css-3">
Div #3
</div>
...
Important : the number of div is dynamic.
But I don't achieve it. I tried with <ng-template let-localHtmlVariable> but didn't work.. Any idea ?

You can use *ngFor structural directive
<div *ngFor="let value of [1,2,3]" class="css-{{value}}">
DIV #{{value}}
</div>

Here is a very situational answer that takes advantages of truhy/falsy values :
<ng-container *ngIf="1 as i">
Number is {{ i }}
</ng-container>
Use it in your classes in the container itself :
<div class="css-{{ i }}">With interpolation</div>
<div [class]="'css-' + i">With input</div>
Here is the stackblitz : https://stackblitz.com/edit/angular-3wm4en?file=src%2Fapp%2Fapp.component.html
EDIT explanation :
In javascript, every value can be transalted to boolean : they are truthy or falsy values.
The quick boolean parse operator is the !! double negation.
Let's try :
console.log(!!'');
console.log(!!0);
console.log(!!5);
When we use this notation, the evaluation use the same principle : it tests if the given value is truthy or falsy. In numbers, 1 being truthy, the test checks out, and the as i notation simply creates a template variable.
For information, falsy values are 0, '', null, undefined, infinity, NaN.

Related

Problem with displaying array length correctly

In an Angular project, I want to loop through filterLifePolicies array because I want to pass via URI the LobDsc property.
The problem is that I also want to output as a number the length of the array but because I loop through each element if the array contains e.g.
3 objects, 3 cards are displayed...I only want one card with the number 3 (array length).
HTML:
<div class="card" *ngFor="let policy of filterLifePolicies">
<a [routerLink]= "['/contracts', policy.LobDsc]"
routerLinkActive="active" class="noLinksDecoration">
<div class="card-body text-center">
<img src="../../assets/images/Component62_1.svg">
<p class="policyTitle">Ζωή & Υγεία</p>
<p class="counter">{{countLife}}</p>
</div>
</a>
</div>
Part of Typescript:
getCustomerPolicies () {
this.http.get<any>('http://localhost:8080/o/mye/pol').subscribe({
next: res => {
this.filterLifePolicies = res.Life.Policies;
console.debug(this.filterLifePolicies);
this.countLife = this.filterLifePolicies.length;
You can do the following, considering countLife variable is assigned the required value.
<div class="card">
<ng-container *ngFor="let policy of filterLifePolicies; index as i">
<a *ngIf="i < 1" [routerLink]="['/contracts', policy.LobDsc]" routerLinkActive="active" class="noLinksDecoration">
<div class="card-body text-center">
<img src="../../assets/images/Component62_1.svg">
<p class="policyTitle">Ζωή & Υγεία</p>
</div>
</a>
</ng-container>
<p class="counter">{{countLife}}</p>
</div>
In the above code snippet, ng-container is being used to iterate through filterLifePolicies in order to access LobDsc value. Since the iteration should not create duplicate HTML div elements with CSS class card-body, an additional check via ngIf is being used to check the index value, such that it should be always lesser than 1.
Although if the LobDsc value is the same for all the values of filterLifePolicies, the recommended approach would be to fetch its value via the dot notation and store it in a variable that can be later binded directly to your template during runtime.

Angular - How to display single "no results" message on no results

I'm having trouble coming up with a way to show my "no results" div element. Basically, I have a list component containg order timeline section components, each one of these section contains order components. Like so:
My orders-list.component.html (check bottom div):
<div class="list-container" [ngClass]="{section: isDeliverySlotsActive === false}">
<label class="list-header" *ngIf="isDeliverySlotsActive === true" style="margin-top: 1.625rem">DELIVERY SLOTS ORDERS</label>
<div [ngClass]="{section: isDeliverySlotsActive === true}" *ngFor="let date of timelines">
<app-orders-list-section
[orders]="orders"
[timeline]="date"
[isDeliverySlotsActive]="isDeliverySlotsActive"
[searchTerm]="searchTerm"
></app-orders-list-section>
</div>
</div>
/* I want to show the below div when there are no results for the search */
<div id="no-results">
<img src="../../../assets/my-orders/no-results.png" alt="No Results" style="margin-top: 6.063rem; margin-bottom: 2.837rem;">
<label class="no-results-text">COULDN'T FIND ANYTHING</label>
<label class="no-results-text weight-medium">Search by order number or customer</label>
</div>
For each section, a filtering method is applied when the user searches for an order using the search bar. If the search term does not correspond to an order in a section, the order is not displayed for that section. If there are no results for that section the section header is also not displayed.
My orders-list-section.component.html:
<div *ngIf="filteredSectionOrders.length > 0">
<label
*ngIf="isDeliverySlotsActive === true"
[ngClass]="{ slots: isDeliverySlotsActive === true }">
{{ timeline | addSectionDateFormat }}
</label>
</div>
<div *ngFor="let order of filteredSectionOrders">
<app-orders-list-item
[order]="order"
[timeline]="timeline"
></app-orders-list-item>
</div>
My filter method in the section component:
filterSectionOrders(searchString: string){
if(!searchString) return;
if(this.hasNumbers(searchString)){
this.filteredSectionOrders = this.filteredSectionOrders.filter(order => order.order_num.toString().indexOf(searchString) !== -1);
}
else{
this.filteredSectionOrders = this.filteredSectionOrders.filter(order => {
if(order.first_name && order.last_name){
let fullName = order.first_name + " " + order.last_name;
if(fullName.toLowerCase().indexOf(searchString.toLowerCase()) !== -1){
return order;
}
}
})
}
}
Given that I apply this filter to each section and not to the list as a whole, how can I find out when there are 0 total results so I can show only one (not for each section) div element with a "no results found" message?
Thank you in advance.
You can easily use *ngIf;else link to ngIf from angular inside your HTML
I am not sure where do you use filteredSectionOrders, because it is not shown in your html, but let's assume your app-orders-list-section has some HTML logic where you use *ngFor to loop through orders and show it properly
so, I guess your code looks something like this
<div class="order" *ngFor="let order of filteredSectionOrders">
<img/>
<p>
{{ order.first_name + ' ' + order.last_name }}
</p>
</div>
This is simplified html how I assume it looks like.
What you can do is next:
<ng-template *ngIf="filteredSectionOrders.length > 0; else noResultsBlock">
// here you insert your code to render orders
<div class="order" *ngFor="let order of filteredSectionOrders">
<img/>
<p>
{{ order.first_name + ' ' + order.last_name }}
</p>
</div>
</ng-template>
<ng-template #noResultsBlock>
<p> No results </p>
</ng-template>
So, this would simple solution
If you want to improve it even more, it would be better to have a new variable, lets say areThereResults, which you will set to true or false, at the end of your method filterSectionOrders, based on filterSectionOrders.length. Then, you would use this new variable inside *ngIf check, instead of filterSectionOrders.length > 0.
Reason for using boolean variable instead of using actual array is detection changes, and will anguar re-render UI inside *ngIf. You can read more about it on Angular documentation, just search for detection changes.

Using a dynamic name for image source in Angular

I have some decks of cards.
I want to display a specific image for each deck, I have an assets folder with all my images.
<div class="decks">
<div *ngFor="let deck of decks" class="deck">
<img
src="../../assets/img/MAGE.png"
MAGE is just an exemple of a deckClass, that name should match deck.deckClass
class="img-responsive"
style="height: 200px;">
<h4> {{deck.deckName}} : {{deck.deckClass}} </h4>
<p *ngFor="let card of deck.deckCards" >
{{ card.name }} : {{ card.manaCost }}
</p>
</div>
</div>
How can I concatenate in a src attribute the deck.deckClass name in a dynamic way?
Consider using the Expression Context
You can wrap the sry attribute with square brackets, this way Angular will know to evaluate the value:
[src]="'../../assets/img/' + deck.deckClass '.png'"
See a demo here: https://stackblitz.com/edit/angular-ua9cfc
I don't have images in there, so they will be shown as broken img's in the demo ...
p.s.: if those images are in your src/assets/ folder, then this should suffice:
[src]="'assets/img/' + deck.deckClass '.png'"

Change dynamically style in Angular with ngfor array data

I want to set the width as dynamically with the data that i am gonna take from the array. But angular doesn't let me set it with usual way. How can i handle it ?
<div *ngFor="let item of products">
<div [style.width.px]="{{ item.size }}" class="Holiday"></div>
</div>
you do not need {{ }} when you're using [].
change [style.width.px]="{{ item.size }}" to [style.width.px]="item.size" and it should work.
Use ngStyle to apply dynamic styles.
<div *ngFor="let item of products">
<div [ngStyle]="{ 'width' : item.size+'px' }" class="Holiday"></div>
</div>
Demo : https://stackblitz.com/edit/angular-fel5sk

Use ng-model to add class to all previous childrens Angular JS

Here is my html code:
<div ng-repeat="(key, a) in items" data-id="{{ Id }}" class="item" id="{{Key}}" ng-click="item($event, key)">
<div class="bubble></div>
<p>
<span> {{ description }}</span>
</p>
</div>
This is the list of items. When we click on the item in the list - all previous elements are set as active (add class).
Here is how it's done:
$scope.item = function(event, key) {
var current;
if ( $(event.target).hasClass('bubble')){
current = $(event.target).closest('#'+ Key);
changeItem(current);
}
function changeItem(current){
$(current).addClass('active');
$(current).prevAll().addClass('active');
$(current).nextAll().removeClass('active');
}
};
Is it possible to use ng-model or something else to set the active value by default form json file? Mean, in json - we have item 3 - marked as active, so how could I add this value to the $scope.item as current? or probably use ng-model?
I have not tried it, but something like this should work.Assuming that the class has to be applied to ng-repeat div. Change your ng-repeat div to:
<div ng-repeat="(key, a) in items" data-id="{{ Id }}" class="item" id="{{Key}}" ng-click="markSelected($index)" ng-class="{'active':selectedIndex<$index}">
</div>
The ng-click call a method markSelected($index) on the controller that sets the currently selected item index. The ng-class uses the current index ($index) and the selectedIndex to determine what class to apply.
The final task is to implement the function which looks like:
$scope.markSelected=function(index) {
$scope.selectedIndex=index;
}
You should stop using jquery and start to think in a more angular way.
There is a directive ng-class that is used to add or remove classes
You can find more information here : https://docs.angularjs.org/api/ng/directive/ngClass
<div ng-repeat="(key, a) in items" data-id="{{ Id }}" class="item" id="{{Key}}" ng-click="item(key)">
<div ng-class="{active : a.active, inactive : a.inactive}"></div>
<p>
<span> {{ description }}</span>
</p>
</div>
$scope.item = function(key){
$scope.items[key].active = true;
$scope.items[key].inactive = false;
}