• Angular实战记录


    当ngModel双向绑定非基本数据类型值时

    子组件中ngModel绑定的值改变时,通过onChangeCallback 传回父组件时,有两种情况:

    1. 基本数据类型:string/number 等变量,父组件中会跟着变化
    2. 非基本数据类型:{}/[]/Date/... 父组件中不会检测到变化

    解决方法:

    创建一个新对象传回:

    this.onChangeCallback(new Date(this.date));
    

    (顺便完善父子组件间双向数据绑定的实现)

    子组件ts:

    import { Component,forwardRef} from '@angular/core';
    import { ControlValueAccessor,NG_VALUE_ACCESSOR, DefaultValueAccessor } from '@angular/forms';
    
    @Component({
      selector: 'iq-timepicker',
      templateUrl: 'timepicker.component.html',
      providers:[{
    	provide:NG_VALUE_ACCESSOR,
    	useExisting:forwardRef(()=>TimePickerComponent),
    	multi:true
      }]
    })
    export class TimePickerComponent implements ControlValueAccessor{
      private date:Date;
      private onChangeCallback: Function = (_: any) => {};
      private onTouchedCallback: any = {};
      
      private triggerChange(){
    	//此时子组件中 this.date 已变化
        let d = new Date(this.date);
        this.onChangeCallback(d);//变化传给父组件
      }
      ...
    
      writeValue(value: Date) {
        if(!value){
          this.date=new Date();
        }else{
          this.date = new Date(value);
        }
      }
      registerOnChange(fn) {
        this.onChangeCallback = fn;
      }
      registerOnTouched(fn) {
        this.onTouchedCallback = fn;
      }
    

    父组件html中使用:

    <iq-timepicker [(ngModel)]="timeVariable"></iq-timepicker>
    

    父组件向子组件传值

    方式:

    1. 属性输入 @Input()
    2. 双向绑定 writevalue

    注意:

    • 传入顺序,先Input后writevalue

    • 两者当传值为非基本数据类型时,都无法监测改变

      Input方式:@Input() set 方法 或者 ngOnChanges,都无法监测改变。像这样:

        //子组件
        import { Component, OnInit, Input, OnChanges,SimpleChanges } from '@angular/core';
      
        @Component({
            selector: "NB-new-list",
            templateUrl: '...',
            styleUrls: ['...']
        })
        export class NBNewListComponent implements OnInit,OnChanges {
      
        	@Input() currency;//币种(此时是基本数据类型)
        	ngOnChanges(changes: SimpleChanges){
                if(changes["currency"]){//币种 变化
        			//变化前的值:changes["currency"].previousValue
        			//变化后的值:changes["currency"].currentValue
                    ...
                }
            }
        }
      

      解决方法:

      可在生命周期ngDoCheck中监测变化:

        //子组件
        import { Component, OnInit, Input, DoCheck } from '@angular/core';
      
        @Component({
            selector: "NB-new-list",
            templateUrl: '...',
            styleUrls: ['...']
        })
        export class NBNewListComponent implements OnInit {
        	
        	beforeList;//暂存上一个清单数据
        	@Input() purchaseData=[];//清单数组(此时是非基本数据类型)
        	ngDoCheck(){
                if (JSON.stringify(this.purchaseData) != JSON.stringify(this.beforeList)) {//当清单变化
        			this.beforeList = JSON.parse(JSON.stringify(this.purchaseData));
        			...
        		}
            }
        }
      

    注意:

    在ngDoCheck中进行input传入值的前后比较时,如果是比较长的对象或数组,建议把上一个值保存为字符串,否则有些变化无法检测到

    形如:

    ngDoCheck() {
    	if (JSON.stringify(this.purchaseData) != this.beforeListStr){//采购清单 变化
    		this.beforeListStr = JSON.stringify(this.purchaseData);
    	}
    }
    

    某些有用的生命周期

    • ngDoCheck:可监测每次input传参对象改变,例子如上
    • ngAfterViewChecked:每次完成界面渲染

    使页面强制刷新

    如同AngularJS中的$apply()

    使用如下:

    import { ChangeDetectorRef} from '@angular/core';
    
    @Component({
    	   selector: "...",
    	   templateUrl: '...',
    	   styleUrls: ['...']
    })
    export class ..Component implements OnInit {
    		
    	constructor(private changeDetectorRef:ChangeDetectorRef) {
        }
    
        Fun(){
        	this.changeDetectorRef.detectChanges();//需要强制刷新
        }
    }
    

    当select下拉选项变化时

    有种情况,在同一个页面,其他操作导致select的下拉选项发生变化,不刷新页面。

    此时需要重置已选的项:

    • 已选的项没有删除,保持选中状态
    • 已选的项删除,则置为”请选择”

    实现难点:

    • 当获取新的下拉列表时,需强制刷新界面;
    • 当判断已选的项目回来时,不仅需要设置双向绑定的值val,还要重置 select对象的已选index和显示text

    html:

    <tr *ngFor="let item of procurementList;index as i">
        <td>
            <select [(ngModel)]="item.MaterialSource" id="materialSource{{i}}" name="materialSource{{i}}" ngModel required>
                <option value=''>请选择</option>
                <option *ngFor="let em of contractList" [ngValue]="em.id">{{em.value}}</option>
            </select>
        </td>
    </tr>
    

    ts:

    import { Component, OnInit, DoCheck,ChangeDetectorRef} from '@angular/core';
    declare var $:any;
    
    @Component({
           selector: "...",
           templateUrl: '...',
           styleUrls: ['...']
    })
    export class ..Component implements OnInit {
    
    procurementList;
    contractList;//合同列表(下拉列表数据)结构为{"id":"","value":""}...
    
    constructor(private changeDetectorRef:ChangeDetectorRef) {
    }
    
    ngDoCheck(){
        if (JSON.stringify(this.contractList) != window.localStorage.getItem("contractList")) {//合同列表变化
            this.contractList = JSON.parse(window.localStorage.getItem("contractList"));
            this.changeDetectorRef.detectChanges();//需要强制刷新
            for(let i=0,len=this.procurementList.length;i<len;i++){
                //重新检查设置已选
                let pro=this.procurementList[i];
                let list=this.OnlyIdContract(pro["MaterialSource"]);
                if(!list){
                    pro["MaterialSource"]="";//为请选择
                }else{
                    pro["MaterialSource"]=list["em"]["id"];//val
                    $("#materialSource"+i)[0].selectedIndex = list["index"]+1; //index
                    $("#materialSource"+i)[0].text=list["em"]["value"]; //text
                }
            }
        }
    }
    OnlyIdContract(id){//根据合同唯一(id)标识 匹配合同项
        let list={
            em:"",//匹配下拉的项
            index:""//匹配已选在现有列表中的index
        }
        let item;
        for(let i=0,len=this.contractList.length;i<len;i++){
            item=this.contractList[i];
            if(item.id==id){
                list.em=item;
                list.index=i;
                return list;
            }
        }
        return "";//已选的已经不在合同列表中 则置空
    	}
    }
    

    用ngModel绑定radio单选框

    当从页面上input的value="true"/"false"获取的值是字符串,此时不能直接做布尔计算,需要函数进行下转化。

    html:

    <span>是否直接写入ERP</span>
    <label>
        <input type="radio" name="directly" [(ngModel)]="saveData.istoerp" #directly="ngModel" value="true" (onClick)="directlyChange($event)">
                    是
     </label>
     <label>
          <input type="radio" name="directly" [(ngModel)]="saveData.istoerp" #directly="ngModel" value="false" (onClick)="directlyChange($event)">
                    否
     </label>
    

    ts:

    directlyChange(e) {//是否写入ERP变化
        if(String(e)=="true"){
            this.saveData.istoerp=Boolean(1);
        }else{
            this.saveData.istoerp=Boolean(0);
        }
    }
  • 相关阅读:
    python中的system函数与编码
    使用signal、setjmp、longjmp进行Linux/Android C异常处理
    ffffffuzzzzzzzzzzzzing
    EIGRP汇总
    JDK
    世界上最健康的生活方式
    Oracle 取两个表中数据的交集并集差异集合
    信息科技风险管理
    BPDU与PortFast
    大胆发言
  • 原文地址:https://www.cnblogs.com/solodancer/p/8361650.html
Copyright © 2020-2023  润新知