Angular 2 ngModel не обновляется после спокойного вызова

У меня есть простой пользовательский компонент, который извлекает имя и фамилию пользователя. Когда пользователь нажимает кнопку отправки, он делает спокойный вызов, извлекает детали и передает обратно моему пользовательскому объекту. Однако в данный момент этого не происходит, и я не уверен, что пошло не так.

Когда я инициирую модель во время инициализации вручную, форма будет правильно отображать данные пользователя. Если я получаю и назначаю значения обратно в форму из вызова Rest API, форма не обновляется.

Я проверил, что данные извлекаются правильно, мой метод диагностики также показывает, что модель правильно отображает данные ответа. Я пробовал zone.run, но форма тоже не обновляется.

ОБНОВЛЕНИЕ Я выяснил, что причина в том, что ответ представляет собой массив объектов. Изменение следующего решило проблему.

this.model = new User().fromJSON(user)[0];

Я не уверен, есть ли способ гарантировать, что моя служба всегда возвращает объект JSON вместо массива объектов?

userservice.ts

 return this.http.post('http://ng2nodejs.azurewebsites.net/api/user', data , {
            headers: authHeader
        })
        .map((response: Response) => { return response.json()});

Мой пользовательский компонент — диагностика правильно отображает данные

{{diagnostic}}

<h1>User Form</h1>
<form (ngSubmit)="f.form.valid && getUser()" #f="ngForm" >                        
    <div class="form-group">
       <label for="firstname">First Name</label>
       <input type="text" id="firstname" [(ngModel)]="model.firstname" name="firstname" >
    </div>
    <div class="form-group">
       <label for="lastname">Last Name</label>
       <input type="text" id="lastname" [(ngModel)]="model.lastname" name="lastname" >
    </div>  

    <button>Submit</button>                
</form>

Модель пользователя, метод fromJSON предназначен для преобразования ответа в мою модель пользователя.

export class User {
  username: string;      
  firstname: string;
  lastname: string; 

  fromJSON(json) {
        for (var propName in json)
            this[propName] = json[propName];
        return this;
    }
}

Мой компонент

 import { Component, NgZone } from '@angular/core';
 import { User } from '../auth/user';
 import { UserService } from '../auth/user.service';

 @Component({
   moduleId: module.id,
   selector: 'app-first',
   templateUrl: './first.component.html',
   styleUrls: ['./first.component.css'],

 })
 export class FirstComponent {
     constructor(private userService: UserService, private zone:NgZone) { }  
     model =  new User();    
     getUser() {             
          this.userService
             .getUser('User123')
             .subscribe((user: Object) => {
                  this.zone.run(() => { 
                     this.model = new User().fromJSON(user);     
                  });  
             });
     }

     get diagnostic() { return JSON.stringify(this.model); }
 }

person CalebC    schedule 06.03.2017    source источник
comment
когда вы вызываете свой метод getUser() ? Вы должны вызывать его onInit или в конструкторе.   -  person mickdev    schedule 06.03.2017
comment
что означает `this.model = new User().fromJSON(user); ` возвращается в консоль. попробуйте зарегистрировать 'this.model'.   -  person candidJ    schedule 06.03.2017
comment
попробуйте this.model = this.model.fromJSON(user); внутри getUser метода   -  person candidJ    schedule 06.03.2017
comment
@mickdev getUser вызывается формой (ngSubmit)=f.form.valid && getUser()   -  person CalebC    schedule 06.03.2017
comment
@candidJ console.log показывает полученный объект пользователя, замена нового пользователя на this.model не сработала.   -  person CalebC    schedule 06.03.2017
comment
Это немного странно для меня. Вы пытались вызвать его в конструкторе, чтобы он установил значение модели при построении компонента?   -  person mickdev    schedule 06.03.2017
comment
@mickdev Да. Я пробовал это также, когда форма инициируется. Похоже, что модель ngForm и модель компонента отделены.   -  person CalebC    schedule 06.03.2017
comment
Я не знаю, является ли какой-либо из этих незначительных упущений причиной вашей проблемы, но исправить их не помешает: 1) кнопка должна быть <button type="submit">; 2) создание экземпляра пользователя было бы чище, чем new User(jsonData), а затем позволить конструктору обрабатывать jsonData; 3) Я не думаю, что вам нужна zone.run(). ПРИМЕЧАНИЕ: так что у вас есть форма, в которой пользователь вводит значения, и когда они отправляют, вы переопределяете значения формы результатом HTTP-вызова? это может быть не оптимально с точки зрения удобства использования.   -  person AngularChef    schedule 06.03.2017
comment
Ты прав. Что касается sitenote, это больше похоже на POC для проверки привязки, когда пользователь нажимает «Отправить», он получает профиль пользователя.   -  person CalebC    schedule 07.03.2017


Ответы (1)


Я не знаю, решит ли это вашу проблему, но я бы дал здесь несколько советов.

Если у вас действительно нет причин использовать классы, я бы посоветовал вам перейти к интерфейсам:

export interface User {
  username: string;      
  firstname: string;
  lastname: string; 
}

и NgZone здесь не нужен.

export class FirstComponent {
  constructor(private userService: UserService) { }  
  model: User = {};   

  getUser() {             
    this.userService
      .getUser('User123')
      .subscribe((user: Object) => {
         this.model = user;
      });
  }
}

И если вы контролируете свой API, почему бы не вернуть только что созданного пользователя, когда вы фактически создаете нового пользователя, чтобы вам не нужно было делать отдельный http-вызов для получения пользователя.

По крайней мере, с приведенным выше этот плункер работает хорошо. Свойства немного отличаются, так как здесь я использую mockbackend.

person AJT82    schedule 06.03.2017
comment
Если это не сработает, вы можете попробовать воссоздать проблему в плункере? - person AJT82; 06.03.2017
comment
Спасибо. Я провел быстрый тест, используя ваши коды, и получаю сообщение об ошибке. Тип «{}» не может быть назначен типу «Пользователь». Свойство firstname отсутствует в типе {} для модели: User = {}; Хотя плунжер, кажется, работает нормально. - person CalebC; 07.03.2017
comment
Да, ошибка возникает, когда вы создаете экземпляр пользовательского объекта? Попробуйте это: model = <User>{}; - person AJT82; 07.03.2017
comment
Не совсем. Основная причина в том, что возвращаемый ответ представляет собой массив, решение таково: this.model = new User().fromJSON(user)[0]; который я обновил в своем вопросе. - person CalebC; 12.03.2017