Angular 1.5 组件:基于组件的应用程序架构

Posted

技术标签:

【中文标题】Angular 1.5 组件:基于组件的应用程序架构【英文标题】:Angular 1.5 components : Component based application architecture 【发布时间】:2017-01-11 16:38:21 【问题描述】:

根据Angular 1.5 documentation 组件应该只控制自己的View 和Data。

除了更改传递给组件的对象的属性,组件应该创建原始数据的内部副本,并在该副本发生更改时使用回调通知父组件。

在这个plunk 中,我创建了一个小演示来说明我的问题。

interface IStudent  
  id: number,
  name: string;


/* SERVICE: StudentService */

public class StudentsService 
  static $inject = ['$q'];
  constructor(private $q: ng.IQService)         
  

  public getStudents() : ng.IPromise<IStudent[]> 
    return this.$q.when([
       id: 1, name: 'Adam' ,
       id: 2, name: 'Ben' 
    ]);
    


/* COMPONENT: student */

class StudentsComponent implements ng.IComponent 
  public template = `<student-list on-selected="$ctrl.onSelected(student)"></student-list>
                     <edit-student student="$ctrl.student" ng-show="$ctrl.student" on-changed="$ctrl.copyChanged(copy)"></edit-student>`;
  public controller = StudentsController;


class StudentsController 
  private student: IStudent;

  protected onSelected(student: IStudent) 
    this.student = student;  
  

  protected copyChanged(copy: IStudent) 
    this.student.name = copy.name;
  


/* COMPONENT: student-list */

class StudentListComponent implements ng.IComponent 
  public template = '<ul><li ng-repeat="student in $ctrl.students"><a ng-click="$ctrl.onClick(student)"> student.name </a></li></ul>';
  public controller = StudentListController;
  public bindings : any = 
    onSelected: '&'
  


class StudentListController 
  protected students: IStudent[];

  static $inject = ['studentsService'];
  constructor(private studentsService: StudentsService) 
  

  public $onInit() 
    this.studentsService.getStudents().then(data => this.students = data);
  

  protected onClick(student: IStudent) 
    this.onSelected( student: student );
  


/* COMPONENT: edit-student */

class EditStudentComponent implements ng.IComponent 
  public template = `<form class="form">
                       <div class="input-group">
                         <label for="#" class="control-label">Original</label>
                         <input type="text" class="form-control" ng-model="$ctrl.student.name" readonly>
                        </div>
                      </form>
                      <form class="form">
                       <div class="input-group">
                         <label for="#" class="control-label">Copy</label>
                         <input ng-change="$ctrl.changed()" type="text" class="form-control" ng-model="$ctrl.copy.name">
                        </div>
                      </form>`;
  public controller = EditStudentController;
  public bindings :any = 
    student: '<',
    onChanged: '&'
  ;


class EditStudentController  
  protected copy: IStudent;

  public $onInit() 
    console.log('EditStudentComponent.$onInit', this.student);
  

  public $onChange() 
    console.log('EditStudentComponent.$onChange', this.student);
    this.copy = angular.copy(this.student);
  

  protected changed() 
    console.log('EditStudentController.changed', this.copy);
    this.onChanged( copy: this.copy );
  


/* Bootstrap */

angular
  .module('app', [])
  .component('students', new StudentsComponent())
  .component('studentList', new StudentListComponent())
  .component('editStudent', new EditStudentComponent())
  .service('studentsService', StudentsService)
;

angular.bootstrap(document, ['app']);

我有一个遍历学生的列表。当用户选择一个学生时,会显示一个文本框,用户可以在其中更改学生的姓名。每当名称更改时,此更改都会传播到更新列表的父组件。

问题是在列表中选择一个学生后,edit-user组件没有初始化,仍然显示组件创建时创建的副本名称(null)。

谁能告诉我如何解决这个问题,以便在单击列表中的学生时,编辑组件会使用所选学生的副本进行初始化?

编辑:更改了 plunk,因为我不小心删除了脚本标签而不是样式标签。

【问题讨论】:

【参考方案1】:

我认为这个笨拙代表了我的问题,但可惜它没有。因为我实现了 $onChange 而不是 $onChanges,所以 plunk 不起作用。我修复了 plunk,使其按预期工作。

我原来的问题的原因是完全不同的。在我的业务应用程序中,我在编辑组件周围使用了另一个带有 ng-transclude 指令的组件,如下所示:

<modal-editor>
    <edit-student data="$ctrl.data">
    <edit-student>
</modal-editor>

由于 edit-student 组件是在模态编辑器组件的隔离范围内定义的,它没有收到对外部范围内的数据变量所做的任何更改(但不知何故,它仍然可以从外部访问数据范围)。

修改 modal-editor 组件使其将数据传递给子组件后,一切都按预期工作:

<modal-editor data="$ctrl.data">
    <edit-student data="$ctrl.data">
    <edit-student>
</modal-editor>

【讨论】:

以上是关于Angular 1.5 组件:基于组件的应用程序架构的主要内容,如果未能解决你的问题,请参考以下文章

Angular 1.5 组件通过 ngRoute 更新父控制器

基于组件拆分 Angular 应用程序的主 JS 包

Angular 1.5 组件似乎没有注册

Angular 1.5,ui-router + 资源 + 组件,stateProvider 找不到组件

在 Angular 1.5 中,如何从子组件编译父组件的 html?

Angular 1.5 组件路由器兄弟组件