Ion-input shows duplicate values

Hey, I try to fill a table with <ion-input> tags, but there are always duplicate numbers showing… (The values in the array are correct.)

capture_004_24112019_220729

<ion-grid>
 <ion-row >
      <ion-col *ngFor="let points of player; let j=index" class="table">
        <ion-input color="primary" [(ngModel)]="player[j]" (ngModelChange)="save()">{{player[j]}}</ion-input>
      </ion-col>
    </ion-row>
  </ion-grid>

It’s the same when I use just a single <ion-input>

Show us what is in the player array?

You are assigning the reference to each player to “points” but using player[j], why not use points?

I want to expand the array in the next step and then it’s easier for me to work with the index.
The array is:
["Sebifix","","","","","","","","",""]

But as said it’s just the same with a simple
<ion-input [(ngModel)]="test">{{test}}</ion-input>

just remove {{player[j]}} from tag

  <ion-input color="primary" [(ngModel)]="player[j]" (ngModelChange)="save()"></ion-input>
1 Like

Thanks, yes, that makes sense^^

But it’s not perfect yet. If I fill a number in the first column, it displays the number in the first and second row and the cursor jumps to the second row.


If I’m typing further it keeps on going like that. Here I’m typing 123:

use this way as @IonicGeoff suggested

<ion-grid>
   <ion-row>
      <ion-col *ngFor="let points of player; let j=index" class="table">
        <ion-input color="primary" [(ngModel)]="points" (ngModelChange)="save()"></ion-input>
      </ion-col>
    </ion-row>
  </ion-grid>

and may i show code of your save() function

Ok, with

<ion-col *ngFor="let points of player; let j=index" class="tabelle">
        <ion-input color="primary" [(ngModel)]="points" ></ion-input>
      </ion-col>

It works. Thanks!
My problem then ist that I want to save the whole array when a number is edited. But it’s ok now, I just have make another step.

The index seems to be the problem. But without the index I don’t know which one of the points has been changed.
How can I deal with this without any index?

I’m having a hard time reconciling these two statements. If you’re going to save the whole array regardless of which point has changed, why do you care which point changed?

It would be helpful to see the entire template and backing controller, or at least abridged versions of them that can actually be compiled by others in order to replicate your situation.

Apply this one hopefully it’ll work.


1. HTML file

<ion-content>

    <button ion-button (click)="addInput()">Add Input</button>
    <ion-item *ngFor="let item of attributes; let i = index">
        <ion-label>Input #{{ i + 1 }}</ion-label>
        <ion-input [(ngModel)]="values[i]" (input)="valChange($event.target.value, i)" type="text"></ion-input>
        <button item-right ion-button icon-only (click)="removeInput(i)">
            <ion-icon name="close"></ion-icon>
        </button>
    </ion-item>

    <button ion-button (click)="getValues()">Get values</button>

</ion-content>

2. Ts file

import { Component } from '@angular/core';
import { IonicPage } from 'ionic-angular';

@IonicPage()
@Component({
    selector: 'some-page',
    templateUrl: 'some-page.html'
})
export class SomePage {
    attributes:Array<number> = [];
    values:Array<string> = [];

    constructor() { }    

    valChange(value:string, index:number):void{
        this.values[index] = value;
    }

    addInput():void{
        this.attributes.push(this.attributes.length);
        this.values.push('');
    }

    removeInput(index:number):void{
        this.attributes.splice(index, 1);
        this.values.splice(index, 1);
    }

    getValues():void{
        console.log(this.values);
    }
}
1 Like

Absolutely, sadly I’m having a hard time too :wink:
How can I save the updated array?

This one works:

<ion-row *ngFor="let player of players">
    <ion-col *ngFor="let points of player">
         <ion-input (ngModel)]="points" (ngModelChange)="save()"></ion-input>
    </ion-col>
</ion-row>

But if I change a value somewhere, then not the array is edited. Only the value in the field has changed and the ‘points’-model there. But the players array is like before, so I can not save it then, because if I load it again the changes are gone.

save(){
  console.log("Players: "+JSON.stringify(this.players))
  localStorage.setItem("players", JSON.stringify(this.players));
}

I hope my specific problem is clear now :wink:

No, not at all. See below:

Ok, I generated a new ionic tab app with ionic start tabs
My tab1.page.ts is:

import { Component } from '@angular/core';

@Component({
  selector: 'app-tab1',
  templateUrl: 'tab1.page.html',
  styleUrls: ['tab1.page.scss']
})
export class Tab1Page {

  players:any=[]

  constructor() { }

ngOnInit() {
  this.players[0] = ["Player 1",'','','','','','','','','' ]
 this.players.push(["Player 2",'','','','','','','','','' ])

  if(localStorage.getItem("players")!=null){
  this.players=JSON.parse(localStorage.getItem("players"))
  }
}

save(){
  console.log("Players: "+JSON.stringify(this.players))
  localStorage.setItem("players", JSON.stringify(this.players));
}

}

and the tab1.page.html is:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Points
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
    
  <ion-grid >
   <ion-row *ngFor="let player of players">
      <ion-col *ngFor="let points of player">
        <ion-input color="primary" [(ngModel)]="points" (ngModelChange)="save()"></ion-input>
      </ion-col>
    </ion-row>
  </ion-grid>

</ion-content>

And I simply want to edit the values in the array and then save the whole array.

I would make Player a proper interface, so that the name is separated out from the scores, instead of mashing everything together into a single array. I would also prefer a separate button for saving, instead of saving the entire shebang on every single little edit, but I assume you have your reasons for wanting to do things this way. Finally, I would not use localStorage. Ionic Storage is better in every situation. localStorage can get erased out from under you with no warning.

All that being said, your primary issue is yet another body on the giant pyre of “things I hate about JavaScript”. When trying to do two-way binding on a nested object, you need to make sure you’re not operating on a transient clone:

<ion-list *ngFor="let player of players; let i = index">
  <ion-item-divider>{{player.name}}</ion-item-divider>
  <ion-item *ngFor="let frame of player.frames; let j = index">
    <!-- transient clone, won't do what you want -->
    <ion-input [(ngModel)]="frame" (ionChange)="save()"></ion-input>
    <!-- real mccoy, is what you want -->
    <ion-input [(ngModel)]="players[i].frames[j]" (ionChange)="save()"></ion-input>
  </ion-item>
</ion-list>

1 Like

Your example code stills breaks with the index on my environment.
But your absolutely right: I’ll do the things in a better way so I’ll don’t need the index.

Thanks for trying to sort this out!
(In ionic 3 it worked I think …)

Define “break”. Obviously you only want the second <ion-input> in there, but I tested it and changes made in the <ion-input> percolate as desired in the save() method.

Also duplicate values:
capture_001_30112019_013007

This is probably a really stupid question, but:

You did read this part, right?

Oh man, I think it was too late for me… Sorry for that and thanks for the help and your patience!