I am creating a list of text and buttons.
I want to identify which button has been clicked in the clicked function.
HTML
<ion-list>
<ion-item ion-item *ngFor="let act of questions.test">
{{act.quote}}
<ion-item>
<button large ion-button item-right (click)="SelectClicked()">Select</button>
</ion-item>
</ion-item>
</ion-list>
TS
this.questions =
{
"test":[
{
"quote": "first row"
}, {
"quote": "second row"
}, {
"quote": "third row"
}, {
"quote": "fourth row"
}
]
}
SelectClicked(detail){
//please help
// which button was clicked ( 1 to 4 ) ?
console.log("SelectClicked" + detail);
}
I am guessing that you want the selected element, that can be done by passing on the event to the handler.
<button (click)="SelectClicked($event)"></button>
Which you can fetch the element from the event with using event.target, event.srcElement or event.currentTarget.
But if you mean to pass along the index or the item of your array, you can just pass on that act object or add an index to the loop...
<ion-item ion-item *ngFor="let act of questions.test; let i = index">
...and pass on the object...
<button (click)="SelectClicked(act)"></button>
...or the id
<button (click)="SelectClicked(i)"></button>
You can pass the "act" value as a parameter to the function like this
<button large ion-button item-right
(click)="SelectClicked(act)">Select
</button>
Related
I have this code for multi buttons inside Ngfor and I want just the clicked button to change its color not all of them, how can I do it please?
.html:
<ion-col size="6" *ngFor="let data of dataArray" >
<ion-card>
<ion-card-header>
<ion-button class="fav-icon2" ion-button [color]="ionicNamedColor (click)="changecolor()" >
<ion-icon name="heart"></ion-icon>
</ion-button>
</ion-card-header>
</ion-card>
</ion-col>
.ts:
public ionicNamedColor: string = 'warning';
changecolor() {
if(this.ionicNamedColor === 'warning') {
this.ionicNamedColor = 'primary'
} else {
this.ionicNamedColor = 'warning'
}
}
here you are using the array named dataArray for showing the buttons on the screen.
Add one more property called clicked in the object used in the dataArray.
So whenever you call the method for changeColor, you just check the property clicked and decide whether to change the color or not.
So your file should be updated with the following code:
<ion-col size="6" *ngFor="let data of dataArray" >
<ion-card>
<ion-card-header>
<ion-button class="fav-icon2" ion-button [color]="data.isClicked?'warning':'primary" (click)="data.isClicked = !data.isClicked" >
<ion-icon name="heart"></ion-icon>
</ion-button>
</ion-card-header>
Here there is not need to add anything in your typescript file.
You are iterating over an array through an ngFor loop, means many button elements could get created, but you have only one single variable for the color attribute, thats why changing for one button, shall change colors for all.
Having said that, you'll have to devise a mechanism so that each rendered button elements through ngFor should get its own reference of color variable. Seeing your code, you should either have the color variable inside the dataArray array, or maintain a separate array of string equal in length to dataArray. Something like this..
public colorArr:string[]= [];
//initially I've populated dataArray with initial colors.
public ngOnInit(){
this.dataArray.forEach(x=>this.colorArr.push('warning'));
}
Your HTML would get modified, like this
<ion-col size="6" *ngFor="let data of dataArray; let i = index" >
<ion-card>
<ion-card-header>
<ion-button class="fav-icon2" ion-button [color]="colorArr[i]" (click)="changecolor(i)" >
<ion-icon name="heart"></ion-icon>
</ion-button>
</ion-card-header>
</ion-card>
</ion-col>
And your changeColor mehtod would get modified like this
changecolor(index) {
if(this.colorArr[index] === 'warning') {
this.colorArr[index] = 'primary'
} else {
this.colorArr[index] = 'warning'
}
}
So in essence we are maintaing colors in separate array for each single button element, without affecting original dataArray.
Another approach could be you create a separate component only for button elements, and pass its relevant data through #input decorators. In that case your this approach of single variable would work.
Thanks.
Try this using button index..
<ion-col size="6" *ngFor="let data of dataArray; index as i;" >
<ion-card>
<ion-card-header>
<ion-button
class="fav-icon2"
ion-button [color]="activeIndex==i ? 'warning' : 'primary'
(click)="setIndex(i)" >
<ion-icon name="heart"></ion-icon>
</ion-button>
</ion-card-header>
</ion-card>
</ion-col>
activeIndex;
setIndex(index) {
this.activeIndex = index:
}
Note: you can change color as per the condition..
What I want to achieve in the end is to see which form controls individually from my form have changed and to create a new object with them assigning a boolean of true if they were changed or false if not. Please see below what I achieved so far, but I don't think this the right approach as when I'll have more from controls my method will become gigantic. If you guys have any idea how I can approach this I would really appreciate it.
my Html
<form [formGroup]="editProfileForm">
<ion-row>
<ion-col>
<ion-input
*ngIf="profileData"
formControlName="firstName"
placeholder="First Name"
></ion-input>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<ion-input
*ngIf="profileData"
formControlName="lastName"
placeholder="Last Name"
></ion-input>
</ion-col>
</ion-row>
</form>
<ion-fab
vertical="bottom"
horizontal="center"
slot="fixed"
(click)="onSubmitEditedProfile()">
<ion-fab-button>
<ion-icon name="checkmark-outline"></ion-icon>
</ion-fab-button>
</ion-fab>
my TS
onSubmitEditedProfile() {
if (this.profileData !== null) {
let updatedFirstName = this.editProfileForm.get("firstName").value;
if (this.profileData.firstname !== updatedFirstName) {
}
console.log("it's the same");
} else {
console.log("it's different")
}
And as my approach means, I'll do the same for lastName and so on
Here is the example where you can iterate each form control and identify either its changed or not based on that populate new array of object.
onSubmitEditedProfile() {
const formValue = [];
// iterate over form controls no matter how many control you have.
Object.keys(this.form.controls).map((key) => {
// create a new parsed object
const parsedValue = {
[key]: this.form.get(key).value, // key is the actual form control name
changed: this.form.get(key).dirty // added changed key to identify value change
}
// push each parsed control to formValue array.
formValue.push(parsedValue)
})
console.log(formValue)
}
Here is the stackblitz working DEMO
Hope this address your requirements.
All you need is just to read dirty value on FormGroup or individual FormControl
https://angular.io/api/forms/AbstractControl#dirty
onSubmitEditedProfile() {
if (!this.editProfileForm.dirty) {
console.log("it's the same");
} else {
console.log("it's different")
}
I have a clarification, Basically i am passing a list from parent page to Ionic modal. In modal, i will iterating over a list. i am basically modifying a property of an object on click of ion-item.
Below is the html code in the modal.
<ion-card *ngFor="let item of items">
<ion-row>
<ion-col size="3">
<ion-img width="80" height="80" [src]="item.imagePath"></ion-img>
</ion-col>
<ion-col size="7" >
<ion-label class="item-name">item.name</ion-label>
<ion-label class="item-price">item.cost</ion-label>
<ion-label class="item-date">item.date</ion-label>
</ion-col>
<ion-col size="2">
<ion-icon class="select-icon" name="add-circle" (click)="updateObj(item)"></ion-icon>
</ion-col>
</ion-row>
</ion-card>
In modal.component.ts
ngOnInit() {
this.items = this.navParams.get("items");
}
dismissModal(){
this.modalCtrl.dismiss();
}
updateObj(object){
if(object){
object.status = true
}
}
i am using navParams to get the list from parent page to the modal. When i click on ion-item i will be calling updateObj method where i am updating the status of object to true. Everything works fine.
But when i update the object in the modal, the original list sent to the modal also gets updated.
Could anyone explain why updating the list in the modal updates the original list. Is it bcoz of using navParams as it referers to the list?
In Parent.component.ts
async openSearchModal(){
const modal = await this.modalCtrl.create({
component: CouponSearchPage,
componentProps: { items: this.itemListData,
}
});
This is how i am passing the list to the modal from parent screen.
When you pass this.itemListData to modal, you are passing the reference of the object.
If you don't want to modify the actual object, you can pass a new object.
Try this:
const modal = await this.modalCtrl.create({
component: CouponSearchPage,
componentProps: { items: { ...this.itemListData},
}
});
I want something like as above shown image. When I click on the edit button then I should able to edit the label( A little about you label ) how can I do it.
<ion-item-divider>
<ion-label>Summary</ion-label>
<button ion-button clear item-end style="font-size:11px;color: #3BABE3;font-weight:bold;">Edit
<ion-icon name="ios-arrow-forward" class="arrow"></ion-icon>
</button>
</ion-item-divider>
<ion-item class="items">
<p style="color:grey;font-size:11px;">A little about you</p>
</ion-item>
The label should be blocked when I click on edit button it should be editable.
I'm assinging "A little about you" to a variable called summary.
<p style="color:grey;font-size:11px;">A little about you</p>
Actually this should be <textarea> instead of <p>
Try using the contenteditale atribute.
<ion-item class="items">
<p contenteditable="true" style="color:grey;font-size:11px;">A little about you</p>
</ion-item>
If you want to bind it to a variable you can do it like this:
<ion-item class="items">
<p [attr.contenteditable]="editable" style="color:grey;font-size:11px;">A little about you</p>
</ion-item>
Where editable is a boolean variable.
I had a similar need / code example and after a while I realized that asking users to edit your ion-label inline of the same view is basically a bad UX.
Consider making that button "edit" of yours to just spawn an alert controller which will contain input field. This is how I did it below and in my case I did not have a special "edit" button - users could click on a title to change its name. But I think you will get the way you can do it in your case
<ion-item *ngFor="let set of sets; index as i">
<button ion-button clear (click)="changeSetTitle( set.title, i)">
<h2>{{ set.title }}</h2>
</button>
<p>{{ set.length }} items</p>
<button ion-button icon-right clear item-end (click)="loadSetComponent(i)">
Manage
<ion-icon name="arrow-forward"></ion-icon>
</button>
</ion-item>
And in ts file:
changeSetTitle(currentTitle, index) {
this.alertOn = true;
let alert = this.alertCtrl.create({
title: 'Change name:',
message: 'current: "'+currentTitle+'"',
inputs: [
{
placeholder: 'type in a new name'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
this.alertOn = false;
}
},
{
text: 'Confirm',
handler: data => {
if (data[0].length === 0) {
this.sets[index].title = currentTitle;
} else {
this.saveRequired = true;
this.sets[index].title = data[0];
}
this.alertOn = false;
}
}
]
});
// small trick to force focus onto alert (not working for iOS unfortunately.)
alert.present().then(() => {
const alertInput: any = document.querySelector('input.alert-input');
alertInput.focus();
return;
});
}
I am new in angular.when I try to fetch value of textbox which is in a loop getting json array in this format - in the formsubmit method if I do console.log(myForm.value) then I get this big list:
[
{
"product-0":"Voltas",
"avi-0":"5",
"def-0":"0",
"quantity-0":3,
"product-1":"Voltas1",
"avi-1":"5",
"def-1":"1",
"quantity-1":3,
"product-2":"Voltas2",
"avi-2":"5",
"def-2":"7",
"quantity-2":1,
"product-3":"Voltas0",
"avi-3":"5",
"def-3":"6",
"quantity-3":1
}
]
can anyone help me to get json in this format
[
{
"product-0":"Voltas",
"avi-0":"5",
"def-0":"0",
"quantity-0":3
},
{
"product-1":"Voltas",
"avi-0":"5",
"def-0":"0",
"quantity-0":3
}
]
in angular 2.thanks in advance.
this is my html code
<form #myForm="ngForm">
<ion-item *ngFor="let productlist of productlists;let i = index">
<ion-row>
<ion-col width-15><input type="hidden" id="hiddenValue" [(ngModel)]="productlist.product" name="product-{{i}}" /> {{productlist.product}}</ion-col>
<ion-col width-25><input type="hidden" id="hiddenValue" [(ngModel)]="productlist.avi" name="avi-{{i}}"/>{{productlist.avi}}</ion-col>
<ion-col width-25><input type="hidden" id="hiddenValue" [(ngModel)]="productlist.def" name="def-{{i}}"/>{{productlist.def}}</ion-col>
<ion-col width-25 class="add">
<button clear (click)="increment(productlist)"><ion-icon name="add-circle" ></ion-icon></button>
<ion-item><ion-input type="number" [(ngModel)]="productlist.quantity" name="quantity-{{i}}" class="quantity"></ion-input></ion-item>
<button clear (click)="decrement(productlist)"><ion-icon name="remove-circle" ></ion-icon></button>
</ion-col>
</ion-row>
</ion-item>
<button ion-button (click)="formSubmit(myForm.value)">submit</button>
</form>
In your template, you have a single form and a single form can only return a single object.
If you want to split that into multiple objects then you need to write code in your submit method to iterate through 'the big list' and create the structure you want:
[ {} ] => [ {}, {}. {} ]
You would have to search for object.keys.substr(0,6) matching 'product'. This is not a good idea even though it could work.
What I suggest instead is that you create nested forms - one form for each item in the list. I suggest you use reactive forms for this, as it is much easier.
This is because you need to create a component that represents a single product in your array:
[ {}, {}, {} ] =
[{product-item}, {product-item}, {product-item}]
ie:
ProductList-Component has a form with ngFor and inside the ngFor you load multiple children, like this:
<product-item *ngFor="let product of productlists"
[product]="product">
</product-item>
Notice that this product-item component will need an #Input, which is a formGroup, eg:
#Input()
public product: FormGroup;
See this article to learn how you can build this.
In particular see the section that starts with "First idea is obviously to extract a component that represents a single item in the form array"