How to toggle click a single elements CSS class in Angular 2? - javascript

I'm looping through an API response and displaying some items (female and male age groups) on a page with the following code:
<ng-container *ngFor="let event of day.availableEvents">
{{ event.name }}
<br>
<ng-container *ngFor="let maleAgeGroup of event.maleAgeGroups">
<span [class.is-active]="status" (click)="updateStatus()" {{ maleAgeGroup }}</span>
</ng-container>
</ng-container>
And, this the JSON data I'm working with:
"days": [
{
"date": "2021-04-14T00:00:00.000Z",
"availableEvents": [
{
"id": 1,
"name": "Event A",
"femaleAgeGroups": ["U13", "U15", "U17"],
"maleAgeGroups": ["U13", "U15", "U17"]
},
{
"id": 2,
"name": "Event B",
"femaleAgeGroups": ["U13", "U15", "U17"],
"maleAgeGroups": ["U13", "U15", "U17"]
},
]
}
]
On click of an age group I want to toggle its status from true or false so that the is-active CSS class is add/removed.
No matter what SO answer I try, I can't get it to work and in most cases end up with an error like 'Cannot assign status to type string'. This is why I've stripped back the above code right to basics - maybe it's because of the way my data is structured?
The example below is what I'm trying to end up with, where the highlighted text has been clicked and is-active class applied:

[class.is-active] needs to 'bind' to a value, it is unclear to me the intent of what you trying to do as a whole, but, each age group needs a state. Thus, you need to update/modify your data either from the server or augment in your component with the status for each age group...
"femaleAgeGroups": [{name:"U13", active:true}, {name:"U15", active:false}, {name:"U17", active:false}], etc..
Then in the template you can bind the css class to the boolean value
<ng-container *ngFor="let maleAgeGroup of event.maleAgeGroups">
<span [class.is-active]="maleAgeGroup.active" (click)="updateStatus(maleAgeGroup)" {{ maleAgeGroup.name }}</span>
</ng-container>
.. and to update you pass the item to update function and update its active state:
updateStatus(item:any): void {
item.active = !item.active;
}

Related

Hide/Show a checkbox based on json value

I have 4 check boxes and I want to hide/show them based on the value that I am getting in my JSON. I'll get only one name of checkbox in my JSON and only that particular checkbox will be shown to user and it'll be marked as checked. How can I do that? Here is my material checkbox code
<div fxLayout="row wrap" class="py-8" fxLayoutAlign="space-evenly">
<mat-checkbox>Fragile</mat-checkbox>
<mat-checkbox>Flyer</mat-checkbox>
<mat-checkbox>Time Stipulated</mat-checkbox>
<mat-checkbox>Gift Wrapped</mat-checkbox>
</div>
Here is my json
Since I am getting name as flyer so only flyer checkbox will be shown to user as checked while all other will not be shown to user.
Not Cleared with your question. You are using Mat-checkbox without using of JSON file
If your Json will be
SampleJson= [
{
Name: "Fragile",
isActive: true
},
{
Name: "Flyer",
isActive: true
},
{
name: "Time Stipulated",
isActive: true
},
{
name: "Gift Wrapped",
isActive: false
},
]
then modify your html to
<div fxLayout="row wrap" class="py-8" fxLayoutAlign="space-evenly">
<mat-checkbox [(ngModel)]="SampleJson[0].isActive">Fragile</mat-checkbox>
<mat-checkbox [(ngModel)]="SampleJson[1].isActive">Flyer</mat-checkbox>
<mat-checkbox [(ngModel)]="SampleJson[3].isActive">Time Stipulated</mat-checkbox>
<mat-checkbox [(ngModel)]="SampleJson[0].isActive">Gift Wrapped</mat-checkbox>
</div>
Hope it works for you. Happy coding

ng-click to pass multiple arrays?

I have a nested json object array and I am able to display Inner Items grouped By Info in HTML using ng-repeat. I have a checkbox in front of each Inner Item where I am handling ng-click event and passing the selected Inner Items to the controller. But now I also wanted to pass Info id in the ng-click event. Can I concatenate the Info array to Inner items array in the ng-click
Here is the json :
[
{
"Info": {
"id": "a1",
"name": "a1-Info",
"InnerInfo": [
{
"name": "xyz"
}
]
},
"InnerItems": [
{ "id": "i1" },
{ "id": "i2" }
]
}
]
<tr ng-repeat=“I in MyData">
<td> {{I.Info.name}}
<table>
<tr><td>
<div ng-repeat=“item in I.InnerItems ">
<input type="checkbox" name="values" ng-click=“getInfo(I);getInnerItems(item)” ng-true-value="1" ng-false-value="0"/>{{item.name}}
</div>
</td>
</tr>
</table>
</td>
</tr>
I need to pass both arrays to one function instead of the above way. Any suggestions?
Use an expression with ng-click to set a property on the controller.
Say you have a property on the controller activeData, then use ng-click like this:
ng-click="activeData = [I , item]"
I have passed multiple parameters to one of my functions itself like getInfo (I, items) and tried to access in controller without having to use any property. It works fine

dynamically Build ng-template using list

I am trying to build ng-template dynamically, In the Data structure, I have a Object that contains list of object of same type or other type of object.
[
{
type: "device",
id: 1,
allowedTypes: ["device","action"],
max: 5,
columns: [
{
type: "action",
id: "1"
},
{
type: "device",
id: 2,
allowedTypes: ["device","action"],
max: 5,
columns: [
{
type: "action",
id: "1"
},
{
type: "action",
id: "2"
}
]
}
]
}
]
My ng-template code:
<script type="text/ng-template" id="and.html">
<div class="container-element box box-red">
<h3>And {{item.id}}</h3>
<ul dnd-list="item.columns"
dnd-allowed-types="item.allowedTypes"
dnd-disable-if="item.columns.length >= item.max">
<li ng-repeat="element in item.columns"
dnd-draggable="element"
dnd-effect-allowed="move"
dnd-moved="item.columns.splice($index, 1)"
dnd-selected="models.selected = element"
ng-class="{selected: models.selected === element}"
ng-include="element.type + '.html'" onload="onloadAction()">
</li>
</ul>
<div class="clearfix"></div>
</div>
</script>
In the ng-template code the first level or different types of object can easily be added, however same type of object does not work properly when added in the 2nd level, it seems the its going in a recursive loop.
This is because the nested ng-template (child) ng-template use of root item.columns from the ng-repeat="element in item.columns".
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'">
</li>
any advise how to resolve this issue.
I have managed to resolve this issue, ng-repeat create a new child scope, however the item from the parent scope is also visible to in the child scope, as this is recursive that mean child template and parent template both have the variable with the same name called item. However the child scope variable item is ignored:
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'">
</li>
in the above snippet the element also has a variable called item, so in the child scope when we call item.columns the item variable of parent is invoked again, to ensure that the item variable of child is not ignored, we need to use ng-init with ng-include and set the current element as item in the child scope as shown below:
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'" ng-init="item=element">
</li>
To read more on this please visit
http://benfoster.io/blog/angularjs-recursive-templates

angularJS - iterating through JSON object

I have a nested JSON "object" called znanja that I want to display on my webpage. It will contain a number of values that I want to make into a list. Basically I'm building a portfolio and want to list my skills. So far I've managed to display the title, and the whole object, or by calling a specific one (for instance {{ znanje.ena }}), but I can't figure out how to display them without the attribute name. If I only call {{ znanje }}, I get them listed like in the JSON. Is there a angularJS directive I can do this with? I'm new to angular, so any help is appreciated.
my view:
<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="znanje in skill.znanja">{{ znanje }}</p>
</div>
my data:
$scope.skills = [
{
title: "Code Knowledge",
znanja : [{
ena : "Javascript",
dva : "HTML",
tri : "CSS",
stiri : "SASS"
}]
},
{
title: "Base Code Knowledge",
znanja : [{
ena : "Java",
dva : "PhP"
}]
},
{
title: "Data",
znanja : [{
ena : "MongoDB",
dva : "MySQL"
}]
}
];
PS: I've named the znanja attributes ena, dva, tri, stiri instead of 1, 2, 3, 4 to be able to call them in the html.
The object which you wanted to apply a loop is nothing but the 1st element in znanja array, so you should be specify skill.znanja[0] instead of skill.znanja.
By doing this you ng-repeat will iterate through each property of object and {{znanje}} will print the value of each property of znanja[0]
Markup
<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="znanje in skill.znanja[0]">{{ znanje }}</p>
</div>
It is possible to get ngRepeat to iterate over the properties of an
object using the following syntax:
<div ng-repeat="(key, value) in skill.znanja"> ... </div>
https://docs.angularjs.org/api/ng/directive/ngRepeat
In order to display the attributes you need a DOM element and a DOM element need a specific value to render so You have to manual at least for one iteration specifically call attributes.
How ever if you have any repetitions you can include it using ng-repeat like you have done.
That is if you want to display each attribute on the html page individually and later want to access it but if you just want to show as json object that will be as easy as passing the json
<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="(key,value) in skill.znanja[0]">{{key}} <b>:</b> {{value}}</p>
</div>
(tested) combined both znanja-object 0 and the value:
<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="(key, value) in skill.znanja[0] ">{{ value }}</p>
</div>
The simplest and best way to solve this issue is by changing your data structure. Simply remove the wrapping array around the lists you iterate on, turning them into object map:
$scope.skills = [
{
title: "Code Knowledge",
znanja : {
ena : "Javascript",
dva : "HTML",
tri : "CSS",
stiri : "SASS"
}
},
{
title: "Base Code Knowledge",
znanja : {
ena : "Java",
dva : "PhP"
}
},
{
title: "Data",
znanja : {
ena : "MongoDB",
dva : "MySQL"
}
}
];
If you did not intend to use that array in any way (all examples contain only one element), then there's no reason for having it there.
There's no need to change anything in your original ng-repeat that way.

default selected items dynamically in several options in angular

i am seeing the example here https://docs.angularjs.org/api/ng/directive/select and this have 3 select with the same value, how can i have different values selected in my options?
i have this:
<li ng-repeat="tarea in tareas">
<input type="checkbox" ng-model="tarea.COMPLETADA" ng-change="updTarea(tarea.ID)"/>
<span class="done-{{tarea.COMPLETADA}}" >{{tarea.NAME}} {{tarea.CLASIFICADORES}}</span>
<select ng-model="selectedOpt"
ng-options="clasificador.NAME for clasificador in clasificadores">
</select>
<button class="buttons delete right" ng-click="delTarea(tarea.ID)"> Eliminar</button>
</li>
so i can have 5,10,15 options, and i want to make a selected item with the value that i have in tarea.CLASIFICADORES, i tried with this
$scope.selectedOpt = $scope.clasificadores[1]
but that make all the options with the same value, like in the example...
how can i make different selected item in my options dynamically with a value i have in my ng-repeat in every item?
i load the data with ajax...
my problem is to set the default selected item with the tarea.CLASIFICADORES. for example, i have a todo list that have a classifier, i want my ng-options to select by default my database value clasifier when the page is load
The problem is, that you are using the same scope variable for all selections. You could store the selected options in an array too like this:
function TestCtrl($scope) {
$scope.items = [
{ id: 1, class: 1 },
{ id: 2, class: 2 },
{ id: 3, class: 1 },
];
$scope.classes = [
{ name: "class 1", id: 1},
{ name: "class 2", id: 2},
{ name: "class 3", id: 3}
];
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="TestCtrl">
<div ng-repeat="currentItem in items">
<select ng-model="selectedClass[$index]" ng-init="selectedClass[$index]=(classes|filter:{id: currentItem.class})[0]" ng-options="class.name for class in classes track by class.id" >
</select>
selected class: {{selectedClass[$index]}}
</div>
</div>
</div>
In this example I take use of the variable $index, which is set by the ng-repeat directive. As the name suggests it contains the current index of the repeat-loop.
UPDATE
I updated the code-snippet so it sets the default value for each select input.
The different items now contain a field with the id of the corresponding class. I initialize the select input with ng-init. With this directive I set selectedClass[$index] which is the selected value for the current item. As we only have the class-id as a property of the items I use a filter to find the corresponding class object with the id (classes|filter:{id: currentItem.class})[0]
To get rid of the filter you could just set the class of each item to the full class-object instead of the id.

Categories