1

I am trying to implement a Component which corresponds to a Bootstrap modal including an input. The input is hooked to a variable in the Component class via [(ngModel)]="..." This works if I enter text inside the input (the variable's value gets updated).

What I want to do is that when this component's show() method gets called the input should be populated with text passed in as a parameter. This does not seem to work and I can't figure out how I can set the initial text passed in as a parameter (without using jQuery).

Here's the relevant code:

editdialog.component.html

<div id="edit_todo_modal" class="modal">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Edit todo</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
              </button>
      </div>
      <div class="modal-body">
        <p>Editing todo: {{currentText}}</p>
        <div class="row">
          <div class="col-md-12">
            <!-- THIS IS WHERE I WANT THE INITAL TEXT -->
            <input id="edit-todo-modal-input" type="text" class="form-control" [(ngModel)]="currentText">
          </div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-primary">Save changes</button>
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

editdialog.component.ts

import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ListComponent } from './list.component';
import { Injectable } from '@angular/core';

declare var jQuery : any;

@Injectable()
@Component({
  selector: 'edit-todo-dialog',
  templateUrl: './editdialog.component.html',
  styleUrls: ['./editdialog.component.css']
})
export class EditTodoDialogComponent{

  currentText: string = "";
  index: number;


  /* I want to use this method to set the initial value */
  show(index: number, text: string): void {
    this.currentText = text;
    this.index = index;

    jQuery("#edit-todo-modal-input").val(this.currentText); // I don't want to use jQuery for showing the initial value, however this works
    jQuery("#edit_todo_modal").modal(); // show bootstrap modal
  }
}

Thanks in advance.

UPDATE

The show()method gets called from this component

import { Component } from '@angular/core';
import { ListService } from './list.service';
import { OnInit } from '@angular/core';
import { EditTodoDialogComponent } from './editdialog.component';

/**
 * The main todo list component
 */

@Component({
  selector: 'list-component',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css'],
  providers: [ListService, EditTodoDialogComponent]
})
export class ListComponent implements OnInit {

  private listService: ListService;
  private editTodoDialog: EditTodoDialogComponent;
  /* ... */


  constructor(listService: ListService, editTodoDialog: EditTodoDialogComponent) {
    this.listService = listService;
    this.editTodoDialog = editTodoDialog;
  }

  ngOnInit(): void {
    this.getTodos();
  }

  /* ... */

  // TO BE IMPLEMENTED

  showEditTodoDialog(index: number) : void {
    this.editTodoDialog.show(index, this.todos[index]);
  }
}

The event is hooked like this:

<li class="list-group-item" *ngFor="let todo of todos; let i = index">
        <div class="todo-content">
          <p class="todo-text" (dblclick)="showEditTodoDialog(i)">
            {{todo}}
          </p>
        </div>
        <div class="todo-close">
          <button (click)="removeTodo(i)" class="btn btn-danger btn-sm">
              <i class="fa fa-remove"></i>
            </button>
        </div>
      </li>

2 Answers2

1

The problem is that you are calling the show from ListComponent by using the componentReference.

You should not do that to pass information between components .

You should either use a @Input and @Output i:e Event Emitters if these component have Parent child relationship else the best way is to go for Shared Services where once you load he data to the service the other component is notified of the change and subscribes to the new data.

More info on how to use parent child link

More info on how to use shared serviceslink

Rahul Singh
  • 19,030
  • 11
  • 64
  • 86
  • @Input did the trick. For future reference, this is the API page that helped me debunk this. https://angular.io/guide/component-interaction – János Schneider Aug 30 '17 at 10:57
0

Have you tried value?:

 <input id="edit-todo-modal-input" type="text" class="form-control" [value]="currentText" ngModel>

For objects, use ngValue:

 <input id="edit-todo-modal-input" type="text" class="form-control" [ngValue]="currentText" ngModel>
  • I did: `` It doesn't do anything. If I remove the ngModel attribute the model doesn't update on input – János Schneider Aug 29 '17 at 10:00
  • You tried this - `` ? notice `ngModel` at the end. It should create a FormControl instance from where you can manipulate values inserted by user –  Aug 29 '17 at 10:08
  • I copypasted this. What happens, is that not only does it not set the default value, but it doesn't seem to update the model either: I do not see the input's value above the input (notice the `

    {{currentText}}

    ` above the input)
    – János Schneider Aug 29 '17 at 10:12