美文网首页
Angular 4.0

Angular 4.0

作者: 壹点微尘 | 来源:发表于2017-11-24 22:59 被阅读141次
    一.课程简介 (注意:这里的AngularJS指的是2.0以下的版本)
    AngularJS的优点:
    • 模板功能强大丰富
    • 比较完善的前端MVC框架
    • 引入了Java的一些概念:比如,依赖注入,单元测试等
    AngularJS的一些问题:
    • 性能
    • 路由
    • 作用域
    • 表单验证
    • JavaScript语言本身问题
    • 学习成本高
    Angular(指的4.0版本)新特性
    • 全新的命令行工具 AngularCLI: 比如,生成一个新项目的骨架,或者生成我们需要的组件的基础代码;或者作为一个开发服务器供我们调试、编译、构建、部署代码、运行自动化的单元测试,等等.
    • 服务器端渲染: 他可以使一个原本需要10s才能加载玩的单页应用,在1s之内呈现在用户面前,他可以使一个单页应用针对每一个视图去做seo优化.
    • 移动和桌面兼容: 可以使用Ionic,React-Native之类的框架
      AngularJS架构
      Angular架构
    Angular与其他流行前端框架的比较
    • React优点
      • 速度快: 虚拟dom (Angular也采用了类似的算法,现在速度与react不相上下了)
      • FLUX架构 (Angular现在也已具备)
      • 服务器渲染 (Angular现在也已具备)
    • Vue对比 之 优点
      • 简单
      • 灵活
      • 性能:(大小只有十几kb,Angular得有50多kb)
    • Vue缺点
      • 个人主导
      • 只关注web
      • 只能依靠第三方框架来实现服务器渲染
    Angular 继承了AngularJS原有的优点,并且吸收了React以及其他框架的优点,祛除了他们的缺点,形成了一套全新的框架.
    Angular
    二. 开始Angular开发
    • Angular程序架构
    Angular程序架构
    • 搭建环境
      • 安装node.js node.js官网
      • 安装 angular-cli sudo cnpm install -g @angular/cli >>>>由于npm总是安装不成功,故使用了淘宝的镜像
      • 检查 angular-cli 是否安装成功 ng -v
        angular/cli 安装成功
      • 创建项目ng new xxx项目名字
      • 创建带路由的项目 ng new xxx --routing
      • 启动项目 ng serve --open
      • 创建组件 ng g component xxx组件
      • 创建一个文件夹并创建组件 ng g component stock/stockManage
        在stock文件夹下生成一个stockManage组件
    项目目录
    项目目录
    component组件组成的必备元素
    组件的必备元素
    其他笔记
    • 声明的数组,在push之前要初始化下
    export class StarsComponent implements OnInit {
      // 外面注入进来的
      @Input()
      rating: number = 0;
      stars: boolean[];
      constructor() {
      }
      ngOnInit() {
        // 数组要初始化一下
        this.stars = [];
        for (let i = 1; i <= 5; i++) {
          this.stars.push(i > this.rating);
        }
      }
    
    }
    
    三.使用Angular Route导航
    • 路由的基础知识
      新建一个导航的项目:ng new router --routing
    • 在路由时传递参数
      • 在查询参数中传递数据

        <a routerLink="/stock" [queryParams]="{id:1}">股票详情</a>
        

        当点击时,导航栏地址中就带上了id参数

        在路由时传递参数
        在跳转到组件中接收这个参数
        export class StockComponent implements OnInit {
        
          private stockId: number;
        
          constructor(private routeInfo: ActivatedRoute) {
        
          }
        
          ngOnInit() {
            this.stockId = this.routeInfo.snapshot.queryParams['id'];
          }
        
        }
        

        在html中调用

        <p>
          这里是股票信息组件
        </p>
        <p>
          股票ID是{{stockId}}
        </p>
        
        执行结果
      • 在路由路径中传递参数
        ①. 在路由中进行配置

        // 路由配置
        const routes: Routes = [
          {
            path:'',
            component: HomeComponent
          },
          {
            path:'stock/:id',
            component: StockComponent
          },
          // 注意: 通配符路由的配置一定要放在最下面
          {
            path:'**',// **(通配符)表示任何路径都可以来匹配
            component: Code404Component
          }
        ];
        

        ②.修改路由连接

        <a [routerLink]="['/stock',1]">股票详情</a>
        

        ③.修改要跳珠组件的ts文件

         export class StockComponent implements OnInit {
        
           private stockId: number;
        
            constructor(private routeInfo: ActivatedRoute) {
        
            }
        
          ngOnInit() {
              this.stockId = this.routeInfo.snapshot.params['id'];
          }
        
        }
        

        ④.显示效果


        在路由路径中传递参数
        注意:当两个跳转到的组件一样时,会因为路由快照的原因,导致路由传递的参数在组件内部不能显示出来;
        解决办法:在该组件的ts文件中
        export class StockComponent implements OnInit {
        
          private stockId: number;
        
          constructor(private routeInfo: ActivatedRoute) {
        
          }
        
          ngOnInit() {
            //解决路由快照的问题
            //每当参数改变时,下面的方法都会被调用一次
            this.routeInfo.params.subscribe((params: Params)=> this.stockId = params['id']);
            this.stockId = this.routeInfo.snapshot.params['id'];
          }
        
        }
        
      • 在路由配置中传递参数
        ①.在路由配置中设置静态数据

         const routes: Routes = [
         {
           path: '',
           component: HomeComponent
         },
         {
           path: 'stock/:id',
           component: StockComponent,
           // 配置一些静态数据
           data: [{
             isPro: true
           }]
         }
        ]
        

        ②.在要跳转到的组件ts文件中

        export class StockComponent implements OnInit {
        
          private stockId: number;
          private isPro: boolean;
        
          constructor(private routeInfo: ActivatedRoute) {
        
          }
        
          ngOnInit() {
            //解决路由快照的问题
            //每当参数改变时,下面的方法都会被调用一次
            this.routeInfo.params.subscribe((params: Params) => this.stockId = params['id']);
            this.stockId = this.routeInfo.snapshot.params['id'];
            this.isPro = this.routeInfo.snapshot.data[0]['isPro'];
          }
        
        }
        

        ③.html文件中

        <p>
          这里是股票信息组件
        </p>
        <p>
          股票ID是{{stockId}}
        </p>
        <p>
          isPro是{{isPro}}
        </p>
        

        ④.显示效果


        在路由配置中传递参数
    • 重定向路由
      在用户访问一个特定的地址时,将其重定向到另一个指定的地址.
      比如:将http://localhost:4200重定向到http://localhost:4200/home
      const routes: Routes = [
        {
          path: '',
          redirectTo: '/home',
          pathMatch: 'full'  // pathMatch: full,路由器将应用重定向,当且仅当导航到“/”。
        },
        {
          path: 'home',
          component: HomeComponent
        }
      ]
      
    • 子路由
      ①.在路由配置中,在children中配置子路由
      {
        path: 'stock/:id',
        component: StockComponent,
        // 配置一些静态数据
        data: [{
          isPro: true
        }],
        children:[
          {
            path:'',
            component:BuyerListComponent
          },
          {
            path:'seller/:id', // 传递参数
            component:SellerListComponent
          }
        ]
      },
      
      ②. 在子路的上一级路由的组件中,设置routerLink插槽
      <!-- ./ : 在当前路由下面去找 -->
      <a [routerLink]="['./']">买家列表</a>
      <a [routerLink]="['./seller', 100]">卖家列表</a>
      <!--插座-->
      <router-outlet></router-outlet>
      

      ③.显示效果


      子路由
    • 辅助路由
      具体参考路由demo
    • 路由守卫
      • CanActivate: 处理导航到某路由的情况.
        使用场景:是否有权限进入到某个路由组件
        ①.路由配置

        {
          path: 'stock/:id',
          component: StockComponent,
          // 路由守卫
          canActivate: [PermissionGuard]
        },
        

        ②.在permission.guard.ts文件中,配置权限

        import {CanActivate} from "@angular/router";
        
        export class PermissionGuard implements CanActivate {
        
           canActivate() {
            var hasPermission: boolean = Math.random() < 0.5;
            if (!hasPermission){
              console.log("用户无权限访问此股票详情");
            }
            return hasPermission; // true 可以进入, false不可以进入
          }
        }
        

        hasPermission为true时,可以跳转到stock路由,为false时,被拦截,不可以进入!

      • CanDeactivate: 处理从当前路由离开的情况.
        具体参考路由demo.

      • Resolve: 在路由激活之前获取路由数据.
        具体参考路由router2.

    四. 依赖注入
    • 什么是依赖注入模式及使用依赖注入的好处

      依赖注入: Dependency Injection 简称 DI 。
      控制反转: Inversion of Control 简称 IOC 。

      使用依赖注入的好处 : 依赖注入会帮你以一种松耦合的方式编写代码,使代码可测性和重用性更高!

    • 介绍Angular的依赖注入实现:注入器和提供器
    • 注入器的层级关系
    • <app-stars [rating]="stock?.rating"></app-stars> // stock?.rating => 当stock存在时,才去访问rating属性

    五. 数据绑定、响应式编程和管道。
    • 数据绑定


      数据绑定
      • 事件绑定


        事件绑定
      HTML属性和DOM属性的关系
      • 少量 HTML 属性 和 DOM 属性 之间有着 1:1的映射,如 id
      • 有些 HTML 属性 没有对应的 DOM 属性, 如 colspan
      • 有些 DOM 属性 没有对应的 HTML 属性,如 textContent
      • 就算名字相同, HTML 属性 和 DOM属性 也不是同一样东西。
      • HTML 属性的值指定了初始值;DOM属性的值表示当前值。
        DOM 属性 的值可以改变;HTML 属性的值不能改变。
      • 模板绑定是通过 DOM属性 和事件来工作的,而不是 HTML 属性。
      HTML属性绑定
      • 基本Html属性绑定:


        基本Html属性绑定.png
      • CSS类绑定:


        CSS类绑定
      • 样式绑定


        样式绑定
    • 双向绑定[(ngModel)]="name" [()] 盒子里面装香蕉

     <input [(ngModel)]="name">
    
    • 响应式编程 : 异步数据流编程
      • 观察者模式与Rxjs
      Observable : 被观察者
      响应式编程

    先导入

    import {Observable} from "rxjs";
    
      //被观察者 
      Observable.from([1, 2, 3, 4])
        .filter(e => e % 2 === 0)
        .map(e => e * e)
        //订阅 (观察者)
        .subscribe(
          //观察者
          e => console.log(e),  // 4 ,  6
          err => console.error(err),
          () => console.log('结束了') // 结束了
        );
    

    观察者后两个回调方法是可选的

    err => console.log(err),
    () => console.log('结束了') // 结束了
    
    • 模板本地变量 #xxxx#来声明
      <input #myField (keyup)="onKey(myField.value)">
      
      ts中代码
      onKey(value) {
        console.log(value);
      }
      

      等同下面的传统方式

      //$event 事件对象  keyup键盘点击
      <input (keyup)="onkey2($event)">
      
      ts中代码
      onkey2(event) {
        console.log(`我是来打怪兽的==${event.target.value}`);
      }
      
    • 响应式编程栗子
      html文件中

      <input [formControl]="searchInput">  // 绑定formControl属性
      

      app.module.ts中引入ReactiveFormsModule

      imports: [
          BrowserModule,
          ReactiveFormsModule
      ],
      

      ts文件中
      先导入

      import {Observable} from "rxjs";
      import {FormControl} from "@angular/forms";
      import 'rxjs/Rx';
      

      具体实现

      export class BindComponent implements OnInit {
      
        searchInput: FormControl = new FormControl();
      
        constructor() {
          this.searchInput.valueChanges
             // 500ms没有收到新的事件,才往下执行
            .debounceTime(500)
            .subscribe(stockCode => this.getStockInfo(stockCode));
        }
      
        ngOnInit() {
        }
      
        getStockInfo(value) {
          console.log(value);
        }
      
      }
      

      实现总结:当用户在搜索框中一直输入内容,此时输入框不会触发搜索功能,当用户输入停下来,超过500ms才会执行搜索功能!

    • 管道 : 负责处理原始值到显示值的转换.比如(GMT时间转换)

      管道符号: |

      Angular4中常用管道 摘抄参考文章
      • ①. 大小写转换管道
        uppercase: 将字符串转换为大写
        lowercase: 将字符串转换为小写

        <p>将字符串转换为大写{{str | uppercase}}</p>
        
        str:string = 'hello'
        

        页面上会显示
        将字符串转换为大写HELLO

      • ②. 日期管道
        date。日期管道符可以接受参数,用来规定输出日期的格式。

        <p>现在的时间是{{today | date:'yyyy-MM-dd HH:mm:ss'}}</p>
        
        today:Date = new Date();
        

        页面上会显示现在的时间是2017年12月05日14时57分53秒

      • ③. 小数管道
        number管道用来将数字处理为我们需要的小数格式
        接收的参数格式为{最少整数位数}.{最少小数位数}-{最多小数位数}
        其中最少整数位数默认为1
        最少小数位数默认为0
        最多小数位数默认为3
        当小数位数少于规定的{最少小数位数}时,会自动补0
        当小数位数多于规定的{最多小数位数}时,会四舍五入

        <p>圆周率是{{pi | number:'2.2-4'}}</p>
        
        pi:number = 3.14159;
        

        页面上会显示
        圆周率是03.1416

      • ④. async 管道:处理异步流

      • ⑤. 自定义管道
        执行命令ng g pipe pipe/xxx 创建xxx管道
        xxx.pipe.ts文件中:

        import {Pipe, PipeTransform} from '@angular/core';
        
        // Pipe 管道装饰器
        @Pipe({
          name: 'multiple' // 管道的名字,可以任意定义
        })
        export class MultiplePipe implements PipeTransform {
        
          transform(value: number, args?: number): any {
            // value: 管道输入进来的原始的值
            // args 可选参数,管道后面跟的 date:'yyyy-MM-dd HH:mm:ss'等
            // 返回 原始值 乘以 参数值
        
            if (!args) {
              args = 1;
            }
            return value * args;
          }
        }
        

        html中调用

        <p>自定义管道{{size | multiple:'4'}}</p>
        

        执行结果为: 28

    • indexOf() 包含

      return list.filter(item => {
          const itemFieldValue = item[field].toLowerCase();
          return itemFieldValue.indexOf(keyword) >= 0; // indexOf()包含
      });
      
    六.组件间通讯
    • 组件的输入输出属性

      • 输入属性 : 适用于父传子
        需要使用@Input() 修饰
        export class StockSearchComponent implements OnInit {
        
          // @Input() 修饰 keyWord 属性是个输入属性
          @Input()
          private keyWord: string;
          constructor() {
          }
          ngOnInit() {
            setInterval(() => {
              this.keyWord = 'xxxx';
            }, 3000);
          }
        }
        
        这样在父子组件嵌套的情况下,父组件给子组件传值
        <div>
          <input placeholder="请输入搜索关键字" [(ngModel)]="search">
          <app-stock-search [keyWord]="search" ></app-stock-search>
        </div>
        
      • 输出属性: 适用于子传父
        在子组件中先引入
        import { EventEmitter } from '@angular/core';
        
        声明属性
        @Output() // 装饰器没有名字
        searchResult: EventEmitter<StockInfo> = new EventEmitter();
        
        @Output('lastPrice') // 也可以给装饰器起名字
        searchResult: EventEmitter<StockInfo> = new EventEmitter();
        
        发射事件
        this.searchResult.emit(stockInfo);
        
        在父组件中 事件绑定(lastPrice)="xxx($event)"
        如果装饰器没有名字
        <app-stock-search  (searchResult)="searchResultHandle($event)"></app-stock-search>
        
        装饰器有名字 lastPrice
        <app-stock-search (lastPrice)="searchResultHandle($event)"></app-stock-search>
        
        在父组件ts文件中实现
        searchResultHandle(stockInfo: StockInfo) {
          this.currentPrice = stockInfo.price;
        }
        
        在父组件中显示
        <div>
             当前价格是{{currentPrice | number:'2.2-2'}}
        </div>
        
    • 使用中间人模式传递数据
      两兄弟间的数据传递,由这两个兄弟所在的父组件充当中间人的角色

      中间人模式
      如上图,son1的一个事件想把值传递到兄弟组件son2中,
      现在son1组件中声明事件属性
      @Output()
      addCart: EventEmitter<StockInfo> = new EventEmitter();
      

      然后发送事件

      buyStock() {
          this.addCart.emit(new StockInfo(this.keyWord, this.price));
      }
      

      在父组件father中,调用该组件,并实现addCartHandler方法

      <son1 (addCart)="addCartHandler($event)"></son1 >
      
      private stockInfo: StockInfo;
      addCartHandler(stockInfo: StockInfo) {
        this.stockInfo = stockInfo;
      }
      

      father组件再将数据传递给son2

      <son2 [stockInfo]="stockInfo"></son2 >
      

      以上就是中间人模式

    • 组件生命周期以及angular的变化发现机制


      生命周期: 红色部分只会被调用一次
    • 生命周期的执行顺序


      生命周期的执行顺序
    • ngOnChanges钩子: 输入属性发生变化的时候调用;
      当组件有@Input()属性时,该属性的初始化是在ngOnChanges中执行的.所以当组件依赖外部输入进来的属性时,它的初始化最好在ngOnInit钩子里面,而不要写在构造函数里面.

    在父组件中调用子组件的方法

    • 方法一

    在父组件中 ,声明一个模板变量

    <app-child #child1></app-child>
    

    在父组件ts文件中,使用@ViewChild()装饰器

    export class AppComponent implements OnInit {
      /**
       * 在父组件 AppComponent 里面,获得子组件的引用
       */
      @ViewChild('child1') // 通过模板变量的名字child1,找到了对应的子组件,并将child1赋值给了下面的child1变量
      child1: ChildComponent;
    
      ngOnInit(): void {
        // 调用子组件的方法
        this.child1.greeting('Tom');
      }
    }
    
    • 方法二

    在父组件的模板上调用子组件的方法

    <!-- 先声明模板变量-->
    <app-child #child2></app-child>
    <!--在父组件的模板上调用子组件的方法-->
    <button (click)="child2.greeting('Jerry')">调用child2的greeting方法</button>
    
    • ngAfterViewInit()ngAfterViewChecked()钩子
      ngAfterViewInit()ngAfterViewChecked() 生命周期是在组件的视图被组装完毕以后调用的;
      如果组件有子组件, 那么只有当所有子组件的视图组装完毕以后,父组件的这两个方法才会被调用;
      不要在这两个方法里改变视图中绑定的东西.如果想改他,也要写在一个定时器(setTimeout)里面,不然会抛出异常;
      ngAfterViewInit() 先调用, ngAfterViewChecked()后调用

    • ng-content 投影

      类似于Vue的插槽
      在子组件定义一个投影

      <div style="border:1px solid red">
        <!--使用 ng-content 组件标记投影点-->
        <ng-content></ng-content>
      </div>
      

      当其父组件调用该子组件时,可以往投影上传递任意内容

      <app-red-border>
        <div>
          我是投影里的内容
        </div>
      </app-red-border>
      
      当然也传递多个投影,并指定每个投影的位置

      在父组件调用子组件时,给投影设置class

      <app-red-border>
        <div class="red">
          我是红框里面的内容
        </div>
        <div class="green">
          我是绿框里面的内容
        </div>
      </app-red-border>
      

      子组件中给设置多个投影位置,并给ng-content设置select属性为父组件中投影的class,

       <div style="border:1px solid red">
        <!--使用 ng-content 组件标记投影点-->
        <ng-content select=".red"></ng-content>
       </div>
      
       <div style="border:1px solid green">
         <ng-content select=".green"></ng-content>
       </div>
      
    • ngAfterContentInit()ngAfterContentChecked()钩子
      这两个钩子针对的是视图中父组件投影进来的那部分内容的;
      ngAfterContentInit():投影进来的内容初始化完毕调用;
      ngAfterContentChecked():专门针对投影进来的内容,做变更检测的;

    • ngOnDestroy 组件销毁
      当切换路由时,会调用该组件销毁钩子;

    • 小结:
      ①.父子组件之间应该避免直接访问彼此的内部,而应该通过输入输出属性来通讯;
      ②.组件可以通过输出属性发射自定义事件,这些事件可以携带任何你想携带的数据;
      ③.在没有父子关系的组件之间,尽量使用中间人模式进行通讯;
      ④.父组件可以在运行时投影一个或多个模板片段到子组件中;
      每个Angular组件都提供了一组生命周期钩子,供你在某些特定的事件发生时执行相应的逻辑;
      ⑤.Angular的变更检测机制会监控组件属性的变化并自动更新视图.这个检测非常频繁并且默认是针对整个组件树的,所以实现相关钩子时要慎重;
      ⑥.你可以标记你的组件树中的一个分支,使其被排除在变更检测机制之外.

    七. 表单处理
    • 模板式表单 (需要引入:FormsModule)
      表单的数据模型是通过组件模板的相关指令来定义的,因为使用这种方式定义表单的数据模型时,我们会受限于HTML的语法,所以,模板驱动方式只适用于一些简单的场景.

    • 响应式表单 (需要引入:ReactiveFormsModule)
      使用响应式表单时,你通过编写TypeScript代码而不是Html代码来创建一个底层的数据模型,在这个模型定义好以后,你使用一些特定的指令,将模板上的html元素与底层的数据模型连接在一起.

    • 响应式表单 和 模板式表单的不同点

      • 不管是哪种表单,都有一个对应的数据模型来存储表单的数据. 在模板式表单中,数据模型是由angular基于你组件模板中的指令隐式创建的. 而在响应式表单中,你通过编码明确的创建数据模型,然后将模板上的html元素与底层的数据模型连接在一起.
      • 数据模型并不是一个任意的对象, 它是一个由angular/forms模块中的一些特定类,如:FormControl, FormGroup, FormArray等组成的. 在模板式表单中, 你是不能直接访问到这些类的.
      • 响应式表单并不会替你生成HTML, 模板仍然需要你自己来编写.
    • 模板式表单例子
      模板式表单的指令都是ng开头的,如:ngForm,ngModel

    <form #myForm="ngForm" (ngSubmit)="createUser(myForm.value)">
      <div>用户名:<input #myNickName="ngModel" ngModel name="nickname" type="text" pattern="[a-zA-Z0-9]+"></div>
      <div>邮箱:<input ngModel name="email" type="email"></div>
      <div>手机号:<input ngModel name="mobile" type="number"></div>
      <div ngModelGroup="passwordInfo">
        <div>密码:<input ngModel name="password" type="password"></div>
        <div>确认密码:<input ngModel name="passwordConfirm" type="password"></div>
      </div>
    
      <button type="submit">注册</button>
    </form>
    
    <br>
    <hr>
    <br>
    
    <div>
      {{myForm.value | json}}
    </div>
    <br>
    <div>
      昵称的值是{{myNickName.value}}
    </div>
    
    模板式表单栗子
    • 响应式表单
      响应式表单的指令都是form开头的,如:formGroup,formControl
      html中代码
    <!--
    与后台的formModel绑定;
    createUser() 不用传值;
    -->
    <form [formGroup]="formModel" (submit)="createUser()">
      <div>昵称:<input formControlName="nickname" type="text" pattern="[a-zA-Z0-9]+"></div>
      <div>邮箱:
        <ul formArrayName="emails">
          <li *ngFor="let email of formModel.get('emails').controls;let i = index">
            <input [formControlName]="I">
          </li>
        </ul>
        <input type="button" (click)="addEmail()" value="添加Email">
      </div>
      <div>手机号:<input formControlName="mobile" type="number"></div>
      <!--与后台的passwordInfo绑定-->
      <div formGroupName="passwordInfo">
        <div>密码:<input formControlName="password" type="password"></div>
        <div>确认密码:<input formControlName="passwordConfirm" type="password"></div>
      </div>
    
      <button type="submit">注册</button>
    </form>
    

    ts中代码

    import {Component, OnInit} from '@angular/core';
    import {FormArray, FormControl, FormGroup} from "@angular/forms";
    
    @Component({
      selector: 'app-reactive-form',
      templateUrl: './reactive-form.component.html',
      styleUrls: ['./reactive-form.component.css']
    })
    export class ReactiveFormComponent implements OnInit {
    
      // 整个表单所有数据
      private formModel: FormGroup;
    
      constructor() {
        this.formModel = new FormGroup({
          nickname: new FormControl(),
          emails: new FormArray([
            new FormControl()
          ]),
          mobile: new FormControl(),
          passwordInfo: new FormGroup({
            password: new FormControl(),
            passwordConfirm: new FormControl()
          })
        });
      }
    
      addEmail() {
        const emails = this.formModel.get('emails') as FormArray;
        emails.push(new FormControl());
      }
      createUser() {
        console.log(this.formModel.value);
      }
    }
    
    响应式表单

    打印结果:


    响应式表单打印结果
    使用FormBuilder可简化上面ts文件中大代码
    import {Component, OnInit} from '@angular/core';
    import {FormArray, FormBuilder, FormControl, FormGroup} from "@angular/forms";
    
    @Component({
      selector: 'app-reactive-form',
      templateUrl: './reactive-form.component.html',
      styleUrls: ['./reactive-form.component.css']
    })
    export class ReactiveFormComponent implements OnInit {
    
      // 整个表单所有数据
      private formModel: FormGroup;
    
      private fb: FormBuilder = new FormBuilder();
    
      constructor() {
        this.formModel = this.fb.group({
          nickname: ['xxx'],
          emails: this.fb.array([
            ['']
          ]),
          mobile: [''],
          passwordInfo: this.fb.group({
            password: [''],
            passwordConfirm: ['']
          })
        });
      }
    
      addEmail() {
        const emails = this.formModel.get('emails') as FormArray;
        emails.push(new FormControl());
      }
    
      createUser() {
        console.log(this.formModel.value);
      }
    
      ngOnInit() {
      }
    
    }
    

    相关文章

      网友评论

          本文标题:Angular 4.0

          本文链接:https://www.haomeiwen.com/subject/zdqqbxtx.html