-2

I made this dropdown with a textarea for input in angular material dialog. There I have only three options in the dropdown(so far)-'English','French' and 'Canadian French'. I have already disabled 'English' by default. Now, for the rest of the remaining options, when I click 'Add new Language' button and select an option(french ; say) and add text I am able to disable the selected option so that when the user adds the third language they cannot select it again. It works fine. Like this (This is without hitting the save button) enter image description here Now the problem starts here. When I select 'French'(say) and hit the save button. And again open the dialog-box. I am again seeing 'French' along with 'Canadian French' in the options for the adding a third language. What do I do to make it inactive and grey-ish like 'English'?enter image description here

This the ts code:

export class ModalAllComponent implements OnInit {

  dialogData: DialogDataModel;

  languages: any[];

  rows: any[];

  item!:any[];

  constructor(
     public dialogRef:MatDialogRef<ModalAllComponent>,
     @Inject(MAT_DIALOG_DATA) public data: DialogDataModel) {
      this.dialogData = data;
      this.rows = this.dialogData.localisedEntities.filter(lang => lang.value,)
      this.languages = this.dialogData.localisedEntities.map(item => ({ code: item.code, title: item.title, canEdit: item.canEdit }))
      console.log(this.dialogData)
    }

  ngOnInit(): void {
  }

  addNewLanguage() {
    this.rows.push({
      code: '',
      title: '',
      value: '',
      canEdit: true
    });
  }

  onChangeValue(ev: any){
    this.rows = this.rows.map(row => {
      if (row.code == ev.value) {
        const lang = this.languages.find(lang => lang.code == ev.value);
        row.title =lang.title;
      }
      return row;
    })

    console.log(this.rows)

    this.languages = this.languages.map(lang => {
      if (lang.code == ev.value) {
        lang.canEdit = false;
        console.log(lang);
      }
      return lang;
    });
    this.isDisabled()
  }

  isDisabled(){
    return this.rows.filter((item) => item.value == '' || item.code == '')
        .length > 0
        ? true
        : false;
  }

  submit(ev:any){
    this.dialogRef.close({data: this.rows});
  }

  back(){
    this.dialogRef.close()
  }

  removeBtn(index:number){
    this.rows.splice(index, 1);
  }
}

I was console-logging at a lot of places and finally manage to draw down to these place where the problem might be happening. In console.log(lang), I saw that, when I selected 'French',the flag canEdit turned to false.But in console.log(this.rows), when I selected 'French',the flag canEdit did not turned to false

How to solve the issue?

The HTML code:

<div>
  <table class="justify-content-between">
    <tr *ngFor="let entity of rows; let i = index">
      <td class="col-1" *ngIf="entity.value!=null">
        <mat-select [(ngModel)]="entity.code" [disabled]="!entity.canEdit"  (selectionChange)="onChangeValue($event)">
          <mat-option *ngFor="let lang of languages" [disabled]="!lang.canEdit" [value]="lang.code">{{ lang.title }}</mat-option>
        </mat-select>
        <!-- <mat-error *ngIf="entity.code.hasError('required')">Please choose an language</mat-error> -->
      </td>
      <td class="col-1" *ngIf="entity.value!=null">
        <textarea style="height: 2rem" class="pl-5" [disabled]="!entity.canEdit" [(ngModel)]="entity.value">{{ entity.value }}</textarea>
        <mat-icon class="pl-2" style="color: red;font-size: 2rem;cursor: pointer;" (click)="removeBtn(i)">close</mat-icon>
      </td>
    </tr>
  </table>
  <div class="d-flex flex-column align-items-center mt-2">
    <button class="form-control" (click)="addNewLanguage()" *ngIf="rows.length < dialogData.localisedEntities.length" [disabled]="isDisabled()">Add new language</button>
      <div class="d-flex pt-2">
        <button class="form-control" [disabled]="isDisabled()" (click)="back()">Discard</button>
        <button class="form-control ml-4 pl-4 pr-4" [disabled]="isDisabled()" (click)="submit($event)">Save</button>
      </div>
  </div>
</div>

This is where the modal is opening:

localiseFoodName() {
    const dialogData = < DialogDataModel > {
      localisedEntities: this.foodModel.localisedName.map((item: any) => {
        if (item.code == 'en') {
          item.canEdit = false;
        } else {
          item.canEdit = true;
        }
        return item;
      }),
    };

    let dialogRef = this.dialog.open(ModalAllComponent, { width: '26.5rem', data: dialogData });

    dialogRef.afterClosed().subscribe(res => {

      if (res && res.data) {
        console.log(res)
        console.log(res.data)
        let temp:any
        this.foodModel.localisedName.map((item:any)=>{
          temp = res.data.find((element:any)=> element.code === item.code);
          if(temp){
            item.value = temp.value
            item.canEdit = temp.canEdit = false
          }
          //console.log(temp)
        })
        const food  = this.foodModel.localisedName
        console.log(food)
      }
    })
  }

When I console.log(food) I could see the canEdit:false. But when I open the modal again, in console.log(this.dialogData) the canEdit is again "True" for the selected item enter image description here

Thanks in advance for the help!

  • If possible, can you create a stackblitz so that people can check the html and the ts file? – dom.macs Oct 01 '21 at 07:19
  • Its not possible to create one. Its part of a very big project. Alot of things are connected –  Oct 01 '21 at 07:21
  • Could you please post the html also I guess rows is your target variable that stores data and languages is the data array – vsnikhilvs Oct 02 '21 at 02:02

3 Answers3

0

On selection, get the selected item inside a function and filter the languages array.

vsnikhilvs
  • 456
  • 1
  • 3
  • 10
  • Can you elaborate? This is the first time I am using dropdown. So I am kinda confused –  Oct 01 '21 at 07:34
  • I have updated the question. If you're unable to understand my problem –  Oct 01 '21 at 17:08
  • I understand your question, Please post the html to have a look at that. – vsnikhilvs Oct 02 '21 at 02:08
  • I have added the HTML –  Oct 02 '21 at 03:30
  • French and the other French will show, because the modal component is getting initialized again. If you want to make it greyish, you need to let the component know that English has already been chosen. What you can try is, when opening the modal after any option is selected, pass the selected data to the modal. By checking this data, you can make the canEdit true or false in the options data. – vsnikhilvs Oct 02 '21 at 11:00
  • I have updated the question. Can you tell me how to solve that issue? –  Oct 02 '21 at 14:53
  • Suppose, you have selected the options English and French and passed the data to the parent component and let the array be 'selected' (say). Next time you open the modal, pass the 'selected' to the modal in the data obj. `this.dialogRef.open(, { data: this.selected })`. Since you are using data as raw, you can pass the data as an object, like ` data: { rawData: 'rawData', selectedData: this.selected }`. By rawData, i meant the lang options that you are sending right now. Then inside the modal, you can check the data.selectedData array and the change the canEdit in the data array. – vsnikhilvs Oct 03 '21 at 01:33
  • `localiseFoodName() { const dialogData = < DialogDataModel > { localisedEntities: this.foodModel.localisedName.map((item: any) => { if (item.code == 'en') { item.canEdit = false; } else { item.canEdit = true; } return item; }), }; let dialogRef = this.dialog.open(ModalAllComponent, { width: '26.5rem', data:{prevData: dialogData, newData: this.temp} }); dialogRef.afterClosed().subscribe(res => { if (res && res.data) { this.temp = res.data } }) }` –  Oct 03 '21 at 04:43
  • I did this. Now, how to seperate `prevData` from `newData` inside the modal? –  Oct 03 '21 at 04:43
  • 1
    Okay,I solved that. It was a really simple answer –  Oct 03 '21 at 05:30
0

Before diving in...

Because, like you said, it's a big project, I feel like it might be hard to diagnose, but I'll point out what I think could be the culprit based on things I've seen before, and I'll update this answer if more details/context come(s) to light.

In the meantime, please check this out: https://stackoverflow.com/help/minimal-reproducible-example.

Look, I know, it's all obvious stuff, I don't mean to insult, but us programmers will often forget these things when we're zeroed-in on a problem and a reminder is often helpful. Bottom line, a minimal reproducible example goes miles for helping the answerers and the question-asker in turn. Whatever progress you can make on that front is deeply appreciated!


What might be going on

This problem feels much better suited to reactive forms than template-driven forms, but you can use template forms. You'd want some logic in the setter that's attached to your 2-way ngModel binding. That's where you'll need to update the canEdit status.

Also I'm suspicious of your subscription. Depending what dialogRef.afterClosed() returns (in terms of how many emissions, what its source is, etc), you might have a lingering subscription problem here. The subscription does not die with the component. And even if it doesn't cause a logic bug, it's going to bloat your memory, slowing down your app.

And in general, I'd recommend finding a way to not be subscribing explicitly, but seeing if you can instead leverage the async pipe and just push any changes via a subject that you .next at the specific point in your event-listening code (i.e. your ngModel-bound setter). The other benefit is that async pipe handles subscription for you, but it also will unsubscribe when the component dies.

I'll come back to update if this doesn't solve your problem and if you are able to provide more context. Sorry, it's just a lot of guesswork right now. More context would be really helpful!

acat
  • 596
  • 6
  • 15
  • I have solved the issue –  Oct 04 '21 at 04:36
  • [link](https://stackblitz.com/edit/angular-vnhbqr?file=src%2Fapp%2Fmodal%2Fmodal.component.html) There is another problem I am facing here(same code). When I hit the delete button I can see that the row is getting deleted, but when I open the modal again the deleted row sows up again –  Oct 04 '21 at 06:56
  • Nvm, It is done! –  Oct 04 '21 at 16:39
-1

Instead of just hard coding item.code == 'en',so that whenever it sees the en it will turn the flag false:

localiseFoodName() {
    const dialogData = < DialogDataModel > {
      localisedEntities: this.foodModel.localisedName.map((item: any) => {
        if (item.code == 'en') {
          item.canEdit = false;
        } else {
          item.canEdit = true;
        }
        return item;
      }),
    };

I just checked, if the value of item is null(empty) with this item.value != null:

localiseFoodName() {
    const dialogData = < DialogDataModel > {
      localisedEntities: this.foodModel.localisedName.map((item: any) => {
        if (item.value != null) {
          item.canEdit = false;
        } else {
          item.canEdit = true;
        }
        return item;
      }),
    };
    console.log(dialogData);


    let dialogRef = this.dialog.open(ModalAllComponent, {
      width: '26.5rem',
      data: dialogData
    });


    dialogRef.afterClosed().subscribe(res => {

      if (res && res.data) {
        console.log(res.data)
         this.foodModel.localisedName.map((item:any)=>{
          this.temp = res.data.find((element:any)=> element.code === item.code);
          if(this.temp){
            item.value = this.temp.value
          }
        })
      }
    })
  }
  • 2
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 03 '21 at 05:37