I am a beginner with angular material. I have written this code so far:
Answer {
id: string;
content: string;
}
<section *ngFor="let opt of step.answers">
<mat-checkbox [checked]="opt.id" (change)="check($event)">
<p [innerHTML]="opt.content"> </p>
</mat-checkbox>
</section>
I still can't figure out how to retrieve the id for every option selected in every stepper and collect them in array
so this is the solution I've found, it's close to #Çağrı proposition but I changed few things since "event" has an attribute checked that I can use without needing to use a variable to save the value of "isChecked"
check(event, opt, userResponse) {
var rep = [];
if (event.checked === true) {
userResponse.push(opt);
}
if (event.checked === false) {
var index: number = userResponse.indexOf(opt);
userResponse.splice(index, 1);
}
}
<section *ngFor="let opt of step.answers" >
<mat-checkbox (change)="check($event,opt,step.userResponse)">
<p [innerHTML]="opt.content"> </p>
</mat-checkbox>
</section>
in [checked] condition u can't put id. It is true false condition. U should add one attribute more of step.answers model which calls ischecked whose initial value is false. and create global array called choosenanswers ,and write
Answer {
id: string;
content: string;
ischecked:boolean=false;
}
then
<section *ngFor="let opt of step.answers">
<mat-checkbox [checked]="opt.ischecked" (change)="check($event)">
<p [innerHTML]="opt.content"> </p>
</mat-checkbox>
</section>
then in check event in components
check(event){
this.choosenanswers=[];
this.step.answers.foreach(x=>{if(x.ischecked){ this.choosenanswers.push(x.id);}})
}
Related
I'm currently working on an Angular frontend with TypeScript. I'm trying to get the checkbox values from the array elements, which I'm iterating through in the HTML file with ngFor, and add those values to the total value. The total value should be displayed on the webpage.
I managed to get the value once a checkbox is selected, and to increase the total value according to the checked checkbox value. The logic for decreasing the total value once a checkbox gets unselected is missing though. That's where I need some help.
Unfortunately I could not find the specific implementation of the substraction logic on unselect. Many SO posts included JQuery which I couldn't use, because the JQuery code did not function despite having no errors (I installed Jquery in Angular with npm).
HTML file:
<span name="total" id="grandtotal">estimation total: {{grandtotal}}</span>
<ul *ngFor="let ticket of tickets">
<li>
<span>Estimation: {{ticket.estimation}}</span>
<b>ID: {{ticket.id}}</b>
<input
type="checkbox"
id="ticket.id"
(click)= "calculateTotal(ticket.estimation)">
<li/>
<ul/>
TypeScript file:
totalValue: number = 0;
public calculateTotal(checkboxValue: number): void {
var checkboxes = <HTMLInputElement> document.getElementById('ticket.id');
if(checkboxes.checked) {
this.totalValue = this.totalValue + checkboxValue;
}
}
You can use an array of tickets to populate a template driven form.
Add a select attribute to your Ticket
type Ticket = {
id: number;
estimation: number;
select: boolean;
};
Fill the array:
tickets: Ticket[] = [
{ id: 1, estimation: 100, select: false },
{ id: 2, estimation: 150, select: false },
];
change the code to loop over all your tickets
public calculateTotal(): void {
let total = 0;
this.tickets.forEach((el) => {
if (el.select) {
total += el.estimation;
}
});
this.grandtotal = total;
console.log('Calc');
}
and change your HTML slightly:
<span name="total" id="grandtotal">estimation total: {{ grandtotal }}</span>
<ul>
<li *ngFor="let ticket of tickets">
<span>Estimation: {{ ticket.estimation }}</span>
<b>ID: {{ ticket.id }}</b>
<b> selection:{{ ticket.select }}</b>
<input
type="checkbox"
id="ticket.id"
[(ngModel)]="ticket.select"
(change)="calculateTotal()"
/>
</li>
</ul>
See working example in stackblitz: https://stackblitz.com/edit/angular-ivy-i7zmv2?file=src/app/app.component.ts
I need some help. I'm trying to disable the rest of the switches if one is selected, as only one is allowed. I've tried doing loops approach but no success. Here is my code.
HTML file
<label class="switcher switcher-success ml-3">
<input
type="checkbox"
class="switcher-input"
(change)="registerProduct(i, $event.target.checked)"
/>
<span class="switcher-indicator">
<span class="switcher-yes">
<span class="ion ion-md checkmark"></span>
</span>
<span class="switcher-no">
<span class="ion ion-md-close"></span>
</span>
</span>
</label>
Ts file
public registerProduct(index, value) {
this.isChecked = value;
// tslint:disable-next-line: prefer-const
this.product = this.products[index];
if (value) {
this.includedProducts.push({
EntityTypeId: '49e185d1-529c-4b7a-a6fb-245649624a14',
EntityTypeName: 'Producto',
EntityId: this.product.ProductId,
EntityName: this.product.ProductName,
Required: true,
});
}
}
You can simply set the value of the checked element in your object.
I assume that you have an array of elements that you then show on your table.
On each elements you can add an attribute that is the checked value as follow
// Array element
let products = [{attribute1:value1,...},{...},...]
// If the array is created by you, just add the attribute by hand
// If you retrieve data from service or anywhere else, map all elements
products = products.map(product => {
return {...product, checked:false}
})
Once you have an array of elements that contains checked values, you can set them to the switches on your template
<label class="switcher switcher-success ml-3">
<input
type="checkbox"
class="switcher-input"
(change)="registerProduct(i, $event.target.checked)"
[checked]="{{value.checked}}" <!-- Here you set the value of your product -->
/>
<span class="switcher-indicator">
<span class="switcher-yes">
<span class="ion ion-md checkmark"></span>
</span>
<span class="switcher-no">
<span class="ion ion-md-close"></span>
</span>
</span>
</label>
So then, on your change method, you can set all the values for all products as false, and set the one identified by the index as true.
I have created a stackblitz to help you to understand.
Another aproach using only [ngModel] and (ngModel)
If you has a variable value you can use
<div *ngFor="let switch of switches">
<input type="checkbox"
[id]="switch.value"
<!--is disabled if our variable<>null and <>switch.value-->
[disabled]="value!=null && value!=switch.value"
<!--is true if our variable "value" is equal to switch.value-->
[ngModel]="value==switch.value"
<!--we equal the variable to switchValue if is checked or null if not-->
(ngModelChange)="value=$event?switch.value:null">
<label [for]="switch.value" [innerHTML]="switch.value"></label>
</div>
NOTE, you can omit the "disabled" if you want to have a serie of switch and only check one at time
To disable all other options when one of them is selected, you could use the following:
template
<div *ngFor="let switch of switches">
<input type="checkbox"
[id]="switch.value"
[disabled]="isSwitchDisabled(switch.value)"
[(ngModel)]="switch.checked">
<label [for]="switch.value" [innerHTML]="switch.value"></label>
</div>
controller
switches = [
{ value: 'First switch', checked: false },
{ value: 'Second switch', checked: false },
{ value: 'Third switch', checked: false },
{ value: 'Fourth switch', checked: false }
];
get selectedOptions() {
return this.switches
.filter(({ checked }) => checked)
.map(({ value }) => value);
}
get isSwitchDisabled() {
return (value: string) =>
this.selectedOptions.length && this.selectedOptions[0] !== value;
}
My example is generic and a bit simplistic, replace <label> with your ion markup and the model with whatever it is you're currently using.
I've demonstrated the principle:
the [disabled] attribute needs to be dynamic. I used a getter returning a function checking the value in real time.
See it working here
If the values of your switches are not unique, you'll probably want to add unique identifiers to them (e.g: id) and use those instead of value in both the id attribute of your <input>s and in the isSwitchDisabled function.
I am making angular application with angular form.
Here i have given a form with input fields first name and last name which will always showing..
After that i am having children which will be displayed upon clicking the add button and the children will get removed on click remove button.
As of now everything works fine.
Here i am making patching of data to the inputs on click option from select box.. The neccessary inputs gets patched..
HTML:
<div>
<form (ngSubmit)="onSubmit()" [formGroup]="form">
<div *ngFor="let question of questions" class="form-row">
<ng-container *ngIf="question.children">
<div [formArrayName]="question.key">
<div *ngFor="let item of form.get(question.key).controls; let i=index" [formGroupName]="i">
<div *ngFor="let item of question.children">
<app-question [question]="item" [form]="form.get(question.key).at(i)"></app-question>
</div>
</div>
<select multiple (change)="changeEvent($event)">
<option *ngFor="let opt of persons" [value]="opt.key">{{opt.value}}</option>
</select>
</div>
</ng-container>
<ng-container *ngIf="!question.children">
<app-question [question]="question" [form]="form"></app-question>
</ng-container>
</div>
<div class="form-row">
<!-- <button type="submit" [disabled]="!form.valid">Save</button> -->
</div>
</form> <br>
<!-- Need to have add and remove button.. <br><br> -->
<button (click)="addControls('myArray')"> Add </button>
<button (click)="removeControls('myArray')"> Remove </button><br/><br/>
<pre>
{{form?.value|json}}
</pre>
</div>
TS:
changeEvent(e) {
if (e.target.value == 1) {
let personOneChild = [
{ property_name : "Property one" },
{ property_name : "Property two" },
]
for (let i = 0; i < personOneChild.length; i++) {
this.addControls('myArray')
}
this.form.patchValue({
'myArray': personOneChild
});
}
if (e.target.value == 2) {
let personTwoChild = [
{ property_name : "Property three" },
{ property_name : "Property four" },
{ property_name : "Property five" },
]
for (let i = 0; i < personTwoChild.length; i++) {
this.addControls('myArray')
}
this.form.patchValue({
'myArray': personTwoChild
});
}
}
addControls(control: string) {
let question: any = this.questions.find(q => q.key == control);
let children = question ? question.children : null;
if (children)
(this.form.get(control) as FormArray).push(this.qcs.toFormGroup(children))
}
removeControls(control: string) {
let array = this.form.get(control) as FormArray;
array.removeAt(array.length - 1);
}
Clear working stackblitz: https://stackblitz.com/edit/angular-x4a5b6-fnclvf
You can work around in the above link that if you select the person one option then the value named property one and property two gets binded to the inputs and in select box the property one is highlighted as selected..
The thing i am in need is actually from here,
I am having a remove button, you can see in demo.. If i click the remove button, one at last will be got removed and again click the last gets removed..
Here i am having two property one and two, if i remove both the inputs with remove button, the the highlighted value person one in select box needs to get not highlighted.
This is actually my requirement.. If i remove either one property then it should be still in highlighted state.. Whereas completely removing the both properties it should not be highlighted..
Hope you got my point of explanation.. If any needed i am ready to provide.
Note: I use ng-select for it as i am unable implement that library, i am making it with html 5 select box.. In ng-select library it will be like adding and removing the option.. Any solution with ng-select library also appreciable..
Kindly help me to achieve the result please..
Real time i am having in application like this:
Selected three templates and each has one property with one,two,three respectively:
If choose a dropdown then the property values for the respective will get added as children.
Here you can see i have deleted the property name three for which the parent is template three and the template three still shows in select box even though i removed its children
Firstly, get a reference to the select, like so:
HTML:
<select multiple (change)="changeEvent($event)" #mySelect>
<option *ngFor="let opt of persons" [value]="opt.key">{{opt.value}}</option>
</select>
TS:
import { ViewChild } from '#angular/core';
// ...
#ViewChild('mySelect') select;
Then, in your remove function, check if all elements have been removed, and if they have, set the value of the select to null
if (array.length === 0) {
this.select.nativeElement.value = null;
}
Here is a fork of the StackBlitz
I am wanting to change the colour of my text with a service and subscription, however I cannot seem to get it to work properly?
I am using [ngClass] to dynamically set characters that are true for 'isActive', but I don't know why I cannot get this to work?
At present, only the first letter is being changed.
Also... I am hoping to change the colour of the highlighted letters changed by the [ngClass].
Stackblitz
html
<div class="container">
<div class="keys" *ngFor="let item of dataKeys">
<div #text class="chars" *ngFor="let char of data[item]" [ngClass]="{'active': char.isActive}">
{{char.name}}
</div>
</div>
</div>
component
#ViewChild('text') private text: ElementRef;
constructor(private service: SettingsService) {
}
ngOnInit() {
this.subscribeToColour();
}
subscribeToColour() {
this.service.getColour.subscribe(res => {
if (this.text) {
this.text.nativeElement.style.color = res;
}
});
}
get dataKeys() {
return Object.keys(this.data);
}
service
export class SettingsService {
default = 'green'
colour = new BehaviorSubject<any>(this.default);
setColour(colour) {
this.colour.next(colour);
}
get getColour(): Observable<any> {
return this.colour;
}
}
As Peter said the view child reference you captured to "text" is only a reference to the first of the divs that you repeated.
As an alternative, you could consider adding the color to the data object:
Eg:
{
"name": "a",
"isActive": true,
"color": "red",
}
And binding to this in your html file - you shouldn't really be manipulating the nativeElement property yourself
You would then update the property in your data object in your service subscriber as appropriate
The #text is only pointing at the div for a. Therefore, this.text.nativeElement.style.color = res; only updates the color for a.
I modified your code a little bit:
my-comp.component.html
<div class="container">
<div class="keys" *ngFor="let item of dataKeys">
<div class="chars" *ngFor="let char of data[item]" [style.color]="char.isActive ? color : 'white'">
{{char.name}}
</div>
</div>
</div>
my-comp.component.ts
color: string = 'white';
subscribeToColour() {
this.service.getColour.subscribe(res => {
this.color = res;
});
}
Note that I got rid of #text in your html file as well as the conditional block in your ts file.
You don't seem to be setting the .isActive variable of any character in your code. That #text is not working how you want it to.
I think you may be overcomplicating this. You can simply change colors by setting them in your service without subscribing to a value.
Try something like:
<div class="container">
<div class="keys" *ngFor="let item of dataKeys">
<div class="chars" *ngFor="let char of data[item]" [ngClass]="{'active': getColour(char.isActive)}">
{{char.name}}
</div>
</div>
</div>
export class SettingsService {
getColour(boolean): string {
if (boolean == true) {
return 'green'; // whatever colour you want.
} else {
return 'red' // whatever you want
}
}
I'm making a pop up in angular with primeng. The content of the pop up depends on two flags controlled by radio buttons. If one is true, a particular HTML has to be rendered and if other is true, other part has to be rendered. But if one is true, other part in not getting cleared form the pop up. My code is something like this:
In .ts file:
part1: boolean = false;
part2: boolean = false;
makeP1True() {
this.part1=true;
this.part2=false;
}
makeP2True() {
this.part2=true;
this.part1=false;
}
in HTML file:
<p-radioButton name="groupname" value="Part1" (onClick)="makeP1True()"></p-radioButton>
<p-radioButton name="groupname" value="Part2" (onClick)="makeP2True()"></p-radioButton>
<div *ngIf="part1">
Show Part 1
</div>
<div *ngIf="part2">
Show Part 2
</div>
You don't have part2 property as in you example
part1: boolean = false;
part1: boolean = false; // just name it to part2
template
<p-radioButton name="groupname" [value]="Part1" label="Part1" (onClick)="makeP1True()"></p-radioButton>
<p-radioButton name="groupname" [value]="Part2" label="Part2" (onClick)="makeP2True()"></p-radioButton>
<div *ngIf="part1">
Show Part 1
</div>
<div *ngIf="part2">
Show Part 2
</div>
component
export class AppComponent {
part1: boolean = false;
part2: boolean = false;
makeP1True() {
this.part1 = true;
this.part2 = false;
}
makeP2True() {
this.part2 = true;
this.part1 = false;
}
}
stackblitz example
As a general note you can solve it with single propert and relay on
p-radioButton to toggle the value
component
export class AppComponent {
part1: boolean ;
}
template
<p-radioButton name="groupname" label="part1" [value]="true" [(ngModel)]="part1"></p-radioButton>
<p-radioButton name="groupname" label="part2" [value]="false" [(ngModel)]="part1"></p-radioButton>
<div *ngIf="part1 === true">
Show Part 1
</div>
<div *ngIf="part1 === false">
Show Part 2
</div>
stackblitz example with single variable
By doing *ngIf="part1" you are actually just checking whether 'part1' is truthy, which means whether it exists or not. However, to see which item is selected, you would need to set a state variable such as selected.
I would suggest you simplify this by using a single function and ngSwitch. Here is a tutorial: https://www.tektutorialshub.com/angular-2-ngswitch-directive/
With the [ngSwitch] directive you can specify an expression to be evaluated. With *ngSwitchCase you can specify the matcher. The syntax would be the closest to your code.
It would look like this:
HTML
<p-radioButton name="groupname"
value="Part1"
(onClick)="setPart('part1')">
</p-radioButton>
<p-radioButton name="groupname"
value="Part2"
(onClick)="setPart('part2')">
</p-radioButton>
<ng-container [ngSwitch]="selected">
<div *ngSwitchCase="'part1'">
Show Part 1
</div>
<div *ngSwitchCase="'part2'">
Show Part 2
</div>
</ng-container>
TS
public selected: string;
public setPart(id: string): void {
this.selected = id;
}
In this case both divs do something like this: *ngIf = "selected === 'partX'.
BTW: <ng-container> lets you use directives such as *ngIf,*ngSwitch and so on without creating a new DOM elements. Great for building conditionals.
You can read up on all of this in the official docs