How to use Angular ngIf diretive to display or hide elements? - html

<div *ngFor = "let item of meusItems, let i=index" [ngClass]="{'selected':item[i] == i}">
<li> Nome: {{item.item.name}}</li>
<li> Nome: {{item.item.descricao}}</li>
<select class="custom-select">
<option *ngFor =" let soldado of meusSoldados"> {{soldado.soldado.name}}</option>
</select>
<button ></button>
</div>
I am using a ngFor to display the items of my database. Inside that div i also show a button and a select, but i only want to display them when the item is selected.
Imagine item 1 is selected, then the button and select is displayed for that item, but all others have no button or select.
I imagine that we can probably do it with a simple ngIf but im not seeing how?
Any help is appreciated.

An li element is not a valid direct child of a div element - only a ul element can be a direct parent of an li. what you really need to do is to nest the content inside the repeating li and have an ng-container with an *ngIf on it to conditionally show the content if the item is selected.
Note that I have followed your logic to determine if the item is selected - but there are better ways of doing that.
Also - spans are inline level elements - so you will need styling to display themn correctly and space them out - I would use flex - with the li having display: flex set on it and perhaps justify-content: space-between to separate out the spans.
<ul class="meus-items-list">
<li *ngFor = "let item of meusItems, let i=index" [ngClass]="{'selected':item[i] == i}">
<span> Nome: {{item.item.name}}</span>
<span> Nome: {{item.item.descricao}}</span>
<ng-container *ngIf="item[i] == i">
<select class="custom-select">
<option *ngFor =" let soldado of meusSoldados"> {{soldado.soldado.name}}</option>
</select>
<button >Click me</button>
</ng-container>
</li>
</ul>
You could also do this with a ul / li nested inside the li
<ul class="meus-items-list">
<li *ngFor = "let item of meusItems, let i=index" [ngClass]="{'selected':item[i] == i}">
<ul>
<li> Nome: {{item.item.name}}</li>
<li> Nome: {{item.item.descricao}}</li>
<li *ngIf="item[i] == i">
<select class="custom-select">
<option *ngFor =" let soldado of meusSoldados"> {{soldado.soldado.name}}</option>
</select>
<button >Click me</button>
</li>
</ul>
</li>
</ul>
You could even do this with CSS alone - just by applying display none to the select and button elements in all li's except for the selected one. This will still have these elements in the DOM so is probably not my first thought as to how to do it.
li:not(.selected) select,
li:not(.selected) button {
display: none;
}

For example this is a sample code how it appears :
HTML :
<div *ngIf="selected" class="alert alert-success box-msg" role="alert">
<strong>List Saved!</strong> Your changes has been saved.
</div>
TS :
export class AppComponent implements OnInit{
(...)
public selected = false;
(...)
saveTodos(): void {
//show box msg
this.selected= true;
//wait 3 Seconds and hide
setTimeout(function() {
this.selected= false;
console.log(this.selected);
}.bind(this), 3000);
}
}

Related

How to assign independent of [(ngModel)] in *ngFor list and select HTML tag

I have a problem with [(ngModel)], it syncs all my select to variable
my variable is selectStations = [];
So, when I select an option inside, it will render all select to select the same one and assign to all slot in a variable (see the picture below, just look at it override all slot that is available)
Typesript:
stations: StationModel[] = [];
selectStations = [];
addSlotSelectStation(){
this.view.loading = true;
this.selectStations.push(null);
console.log(this.selectStations);
this.view.loading = false;
}
addSelectStation(index: number, stationId: string) {
console.log(index);
this.selectStations[index] = stationId;
}
deleteSelectStation(index: number): void{
this.selectStations.splice(index, 1);
console.log('delete index', index);
}
HTML:
<button class="btn btn-primary" (click)="addSlotSelectStation()">
add slot
</button>
<!-- List Group All -->
<ul class="list-group overflow-auto">
<!-- Loop List All Select Station -->
<li
*ngFor="let selectStation of selectStations; let index = index"
class="list-group-item"
>
<div class="form-inline">
<!-- Order Number -->
<span class="mr-3">{{ index + 1 }}</span>
<!-- Selection Dropdown -->
<select
#selectnow
class="form-control bg-light col mr-3"
name="selectStation[{{index}}]"
formControlName="selectStation"
size=1
[(ngModel)]="selectStations[index]"
(change)="addSelectStation(index, selectnow.value)"
>
<option selected value="">choose station...</option>
<option
*ngFor="let station of stations"
[value]="station.id"
>
{{ station.name }}
</option>
</select>
<!-- For test debug reasons -->
<div>{{ selectStations[index] }}</div>
<div>{{ index }}</div>
<!-- Delete Select Station -->
<button
class="btn btn-outline-info"
(click)="deleteSelectStation(index)"
>
X
</button>
</div>
</li>
</ul>
Result:
So That's the problem, I want it just select only one, and assign value only one each selector, not override another selector value.
[Solved] I change it from [(ngModel)] to use FormArray. That's very useful when it come across iterating in the list of input/dropdown and etc.
This Link is super useful, Check it out! :)
Angular Reactive Forms: The Ultimate Guide to FormArray

Angular - css style changes in the list of objects in *ngFor

I have two components, parent:
<ng-container *ngIf="itemList != null">
<div *ngFor="let item of itemList">
<component-item [componentItem]="item"></component-item>
</div>
</ng-container>
and child (component-item):
<div class="row myClass" [ngClass]="{'selected': isSelected }" (click)="method()">
...
</div>
As a result I have list of items. I have two css styles: default and "selected". I would like to change styles of items after clicking on them like: when I click on the first item it should change to "selected" and then after clicking second item it should change to "selected" and the first one return to the default. My variable "isSelected" is a boolean type and I change its value on "true" in "method()". How can I change its value on "false" when I select another item from the list?
Try like this, it may work
In component.ts File
cssEnabled:any="";
private method(itemName:string)
{
this.cssEnabled=itemName;
}
In compontent.html :
<div class="row myClass" [ngClass]="{'selected': componentItem==cssEnabled}" (click)="method(componentItem)">
...
</div>

display multiple nested data with angular6

I'm receiving JSON data from an API which has some child objects as well. The API has a menu level and down the menu, it's having meals. What I want to do is to display meals relating to each menu under the menu
JSON from API
[{"id":6,"name":"Menu 1","serveDate":"2019-05-10","meals":[{"id":13,"name":"Rice with Stew","description":"rice","image":"","mealType":"BREAKFAST","unitPrice":5,"status":"ENABLED"}]},{"id":5,"name":"Menu 2","serveDate":"2019-06-10","meals":[{"id":13,"name":"Corn Flakes,"description":"Flakes","image":"","mealType":"BREAKFAST","unitPrice":5,"status":"ENABLED"}]},{"id":4,"name":"Menu 3","serveDate":"2019-07-10","meals":[]}]
HTML
<div *ngFor="let item of menuList">
<h2>Menu</h2>
{{item.name}} - {{item.servate}}
<h2 *ngFor="let item of menuList.meals">Meals</h2>
{{item.name}} - {{item.mealType}}
</div>
JS
getMenus() {
this.menuServices.menuList(this.pagedData)
.subscribe(
response => {
if (response && response.code === HttpStatus.OK) {
this.menuList = response.data;
}
},
);
}
Any help on how to make this work correctly the way it should work?
<div *ngFor="let menu of menuList">
<h2>Menu</h2>
{{menu.name}} - {{menu.servate}}
<h2>Meals</h2>
<ng-container *ngFor="let meal of menu.meals">
{{meal.name}} - {{meal.mealType}}
</ng-container>
</div>
Using this way you don't have to add unnecessary divs or any other html tag for looping in angular.
this is the perfect way to do nested loops without changing your html
No need to access the main list as you have your meals array in the item object.
Change HTML Code to:
<div *ngFor="let item of menuList">
<h2>Menu</h2>
{{item.name}} - {{item.servate}}
<h2>Meals</h2>
<div *ngFor="let item of item.meals">
{{item.name}} - {{item.mealType}}
</div>
</div>
When you're doing something like let item of menuList that means the item variable should be used to refer to an individual item within your loop. To avoid confusion, I'd also recommend naming these item vars for nested loops differently.
Another important thing to keep in mind that all the markup that you want to be output for each array item should be wrapped with an element with *ngFor. It's not the case with your <h2> tag being printed for each meal, but not the meal description.
Edit the template as follows:
<div *ngFor="let menuItem of menuList">
<h1>Menu</h1>
<h2>{{menuItem.name}} - {{menuItem.serveDate}}</h2>
<p>maybe description here</p>
<h3>Meals</h2>
<p *ngFor="let mealItem of menuItem.meals">{{mealItem.name}} - {{mealItem.mealType}}</p>
</div>

Create single Dropdown with this div using css only

How can I turn this into a single dropdown menu ? Right now I have it set with single buttons for each li.
I just want to make it turn into a single dropdown for all of them.
For smaller screens, prefer css example if you can.
<div class="col-md-3">
<ul class="pc-scroller">
<span>GO TO</span>
<li class="pc-welcom">Welcome</li>
<li class="pc-bebidasbeverages-114">Beverages</li>
<li class="pc-traditional-style-breakfast-114">Traditional Breakfast</li>
<li class="pc-mexican-style-breakfast-114">Mexican Breakfast</li>
<li class="pc-mexican-plates-114">Mexican Plates</li>
<li class="pc-botanasappetizers-114">Appetizers</li>
<li class="pc-mariscosseafood-114">Seafood</li>
<li class="pc-parrilladabarbecue-114">Barbecue</li>
<li class="pc-kids-plates-114">Kid's Plates</li>
<li class="pc-postresdesserts-114">Desserts</li>
</ul>
</div>
Check this
https://jsfiddle.net/1fxq39gj/2/
<div class="col-md-3">
<select class="pc-scroller">
<option >GO TO</option>
<option value="welcome" class="pc-welcom">Welcome</option>
<option value="beverages" class="pc-bebidasbeverages-114">Beverages</option>
<option value="traditional" class="pc-traditional-style-breakfast-114">Traditional Breakfast</option>
<option value="mexican" class="pc-mexican-style-breakfast-114">Mexican Breakfast</option>
<option value="plates" class="pc-mexican-plates-114">Mexican Plates</option>
<option value="appetizers" class="pc-botanasappetizers-114">Appetizers</option>
<option value="seafood" class="pc-mariscosseafood-114">Seafood</option>
<option value="barbecue" class="pc-parrilladabarbecue-114">Barbecue</option>
<option value="kid" class="pc-kids-plates-114">Kid's Plates</option>
<option value="desserts" class="pc-postresdesserts-114">Desserts</option>
</select>
</div>
unfortunately the way that the current HTML is set up a pure CSS solution is hard. However, jQuery has a fairly easy solution, and it can do that without going in and changing the actual HTML. Here is the jQuery that you will need to get this working:
// If the span is clicked
$(".pc-scroller > span").click(function() {
// Check to see if the screen is small
if ($(window).width() < 500) {
// Toggle hide/show all list items
$(".pc-scroller > li").toggle();
}
});
// When the screen is resized
$(window).resize(function(){
// If the screen is small, hide all list items
if ($(window).width() < 500) {
$(".pc-scroller > li").hide();
// If the screen is larger, show all list items
} else {
$(".pc-scroller > li").show();
}
});
I have also posted a jsfiddle with this working.

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;
}