Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/32.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用ngModel在angular 6中创建自定义输入组件?_Angular - Fatal编程技术网

如何使用ngModel在angular 6中创建自定义输入组件?

如何使用ngModel在angular 6中创建自定义输入组件?,angular,Angular,由于我使用的输入有很多相同的指令和应用的.css类,因此我想将重复的代码提取到一些组件中,如下所示: @Component({ selector: "app-input", template: ` <div class="..."> <input type="..." name="..." class="..." [(ngModel)]="value" someDirectives...> <label for="..."

由于我使用的输入有很多相同的指令和应用的.css类,因此我想将重复的代码提取到一些组件中,如下所示:

  @Component({
  selector: "app-input",
  template: `
    <div class="...">
      <input type="..." name="..." class="..." [(ngModel)]="value" someDirectives...>
      <label for="...">...</label>
    </div>
  `,
  ...
  })
  export class InputComponent implements OnInit {
    // some implementation connecting external ngModel with internal "value" one
  }
@组件({
选择器:“应用程序输入”,
模板:`
...
`,
...
})
导出类InputComponent实现OnInit{
//外部NGM模型与内部“价值”模型连接的一些实现
}
这里的问题是创建一个组件,使其可以作为普通输入与ngModel一起使用:

<app-input [(ngModel)]="externalValue" ... ></app-input>


在angular 6中是否可以更好地实现这一点?

您可以使用@Input指令将externalValue传递到组件中并与其绑定

这里有一个代码:

  @Component({
  selector: "app-input",
  template: `
    <div class="...">
      <input type="..." name="..." class="..." [(ngModel)]="externalValue" someDirectives...>
      <label for="...">...</label>
    </div>
  `,
  })

  export class InputComponent implements OnInit {
     @Input('externalValue') externalValue : any;
  }
@组件({
选择器:“应用程序输入”,
模板:`
...
`,
})
导出类InputComponent实现OnInit{
@输入('externalValue')externalValue:any;
}
在父组件中,您可以像这样使用它:

<app-input [externalValue]="externalValue" ... ></app-input>

您可以使用shareservice,它可以在两个组件之间进行通信,而无需使用以下输入或输出

服务

import {Injectable} from '@angular/core';

@Injectable()
export class ShareService {
   public data: string;

   setData(newdata : string){
       this.data = newdata;
   }

   clearData(){
       this.data = '';
   }
}
export class PageA {
    constructor(private shareService: ShareService, private router: Router){
    }
    gotoPageB(){
        this.shareService.setData("Sample data");
        this.router.navigate(['pageb']);  
    }

}
export class PageB {
    constructor(private shareService: ShareService){ }

    get somedata() : string {
      return this.shareService.data;
    }
}
设置值的组件

import {Injectable} from '@angular/core';

@Injectable()
export class ShareService {
   public data: string;

   setData(newdata : string){
       this.data = newdata;
   }

   clearData(){
       this.data = '';
   }
}
export class PageA {
    constructor(private shareService: ShareService, private router: Router){
    }
    gotoPageB(){
        this.shareService.setData("Sample data");
        this.router.navigate(['pageb']);  
    }

}
export class PageB {
    constructor(private shareService: ShareService){ }

    get somedata() : string {
      return this.shareService.data;
    }
}
获取值的组件

import {Injectable} from '@angular/core';

@Injectable()
export class ShareService {
   public data: string;

   setData(newdata : string){
       this.data = newdata;
   }

   clearData(){
       this.data = '';
   }
}
export class PageA {
    constructor(private shareService: ShareService, private router: Router){
    }
    gotoPageB(){
        this.shareService.setData("Sample data");
        this.router.navigate(['pageb']);  
    }

}
export class PageB {
    constructor(private shareService: ShareService){ }

    get somedata() : string {
      return this.shareService.data;
    }
}

这里的关键是在获取值的组件中使用getter属性(本例中为PageB),以便在数据服务值更改时随时更新它

不久前我遇到了同样的问题,我想分享一个使用Angular 2+的最小示例

对于较新的角度版本,有一个简化的方法(向下滚动)


角度2+ 假设您希望在应用程序中的任何位置使用以下代码:

<app-input-slider [(ngModel)]="inputSliderValue"></app-input-slider>
  • 现在我们必须在
    输入slider.component.ts
    文件中做一些工作:

    import {Component, forwardRef, OnInit} from "@angular/core";
    import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
    
    @Component({
        selector: "app-input-slider",
        templateUrl: "./input-slider.component.html",
        styleUrls: ["./input-slider.component.scss"],
        providers: [{
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => InputSliderComponent),
            multi: true
        }]
    
    })
    export class InputSliderComponent implements ControlValueAccessor {
    
     /**
      * Holds the current value of the slider
      */
     value: number = 0;
    
     /**
      * Invoked when the model has been changed
      */
     onChange: (_: any) => void = (_: any) => {};
    
     /**
      * Invoked when the model has been touched
      */
     onTouched: () => void = () => {};
    
     constructor() {}
    
     /**
      * Method that is invoked on an update of a model.
      */
     updateChanges() {
         this.onChange(this.value);
     }
    
     ///////////////
     // OVERRIDES //
     ///////////////
    
     /**
      * Writes a new item to the element.
      * @param value the value
      */
     writeValue(value: number): void {
         this.value = value;
         this.updateChanges();
     }
    
     /**
      * Registers a callback function that should be called when the control's value changes in the UI.
      * @param fn
      */
     registerOnChange(fn: any): void {
         this.onChange = fn;
     }
    
     /**
      * Registers a callback function that should be called when the control receives a blur event.
      * @param fn
      */
     registerOnTouched(fn: any): void {
         this.onTouched = fn;
     }
    
    import {Component, forwardRef, OnInit} from "@angular/core";
    
    @Component({
        selector: "app-input-slider",
        templateUrl: "./input-slider.component.html",
        styleUrls: ["./input-slider.component.scss"],
        providers: []
    })
    export class InputSliderComponent {
    
        /**
         * Holds the current value of the slider
         */
        @Input() inputSliderValue: string = "";
    
        /**
         * Invoked when the model has been changed
         */
        @Output() inputSliderValueChange: EventEmitter<string> = new EventEmitter<string>();
    
     }
    
    }

  • 当然,您可以使用这个类添加更多的功能和值检查,但我希望它能给您带来一些想法

    快速解释:

    技巧是在类的decorator上添加provider
    NG\u VALUE\u访问器
    ,并实现
    ControlValueAccessor

    然后我们需要定义函数
    writeValue
    registerChange
    registerTouched
    。创建组件时直接调用后两个。这就是为什么我们需要修改变量(例如
    onChange
    onTouched
    ),但您可以随意命名它们

    最后,我们需要定义一个函数,让组件知道如何更新底层的ngModel。我使用函数
    updateChanges
    做到了这一点。无论是从外部(这就是为什么在
    writeValue
    中调用它)还是从内部,只要值发生变化,都需要调用它(这就是为什么从html
    ngModelChange
    调用它)


    角度7+ 虽然第一种方法仍然适用于较新的版本,但您可能更喜欢以下需要较少键入的版本

    在早期,您可以通过在外部组件中添加如下内容来实现双向绑定:

    <app-input-slider [inputSliderValue]="inputSliderValue" (inputSliderValueChange)="inputSliderValue = $event"></app-input-slider>
    
  • 现在我们必须在
    输入slider.component.ts
    文件中做一些工作:

    import {Component, forwardRef, OnInit} from "@angular/core";
    import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
    
    @Component({
        selector: "app-input-slider",
        templateUrl: "./input-slider.component.html",
        styleUrls: ["./input-slider.component.scss"],
        providers: [{
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => InputSliderComponent),
            multi: true
        }]
    
    })
    export class InputSliderComponent implements ControlValueAccessor {
    
     /**
      * Holds the current value of the slider
      */
     value: number = 0;
    
     /**
      * Invoked when the model has been changed
      */
     onChange: (_: any) => void = (_: any) => {};
    
     /**
      * Invoked when the model has been touched
      */
     onTouched: () => void = () => {};
    
     constructor() {}
    
     /**
      * Method that is invoked on an update of a model.
      */
     updateChanges() {
         this.onChange(this.value);
     }
    
     ///////////////
     // OVERRIDES //
     ///////////////
    
     /**
      * Writes a new item to the element.
      * @param value the value
      */
     writeValue(value: number): void {
         this.value = value;
         this.updateChanges();
     }
    
     /**
      * Registers a callback function that should be called when the control's value changes in the UI.
      * @param fn
      */
     registerOnChange(fn: any): void {
         this.onChange = fn;
     }
    
     /**
      * Registers a callback function that should be called when the control receives a blur event.
      * @param fn
      */
     registerOnTouched(fn: any): void {
         this.onTouched = fn;
     }
    
    import {Component, forwardRef, OnInit} from "@angular/core";
    
    @Component({
        selector: "app-input-slider",
        templateUrl: "./input-slider.component.html",
        styleUrls: ["./input-slider.component.scss"],
        providers: []
    })
    export class InputSliderComponent {
    
        /**
         * Holds the current value of the slider
         */
        @Input() inputSliderValue: string = "";
    
        /**
         * Invoked when the model has been changed
         */
        @Output() inputSliderValueChange: EventEmitter<string> = new EventEmitter<string>();
    
     }
    
    从“@angular/core”导入{Component,forwardRef,OnInit};
    @组成部分({
    选择器:“应用程序输入滑块”,
    templateUrl:“./input slider.component.html”,
    样式URL:[“/input slider.component.scss”],
    提供者:[]
    })
    导出类InputSliderComponent{
    /**
    *保存滑块的当前值
    */
    @Input()inputSliderValue:string=“”;
    /**
    *当模型已更改时调用
    */
    @Output()inputSliderValueChange:EventEmitter=新的EventEmitter();
    }
    
  • 重要的是,输出属性(EventEmitter)与带有附加字符串
    Change
    的输入属性具有相同的名称


    如果我们比较这两种方法,我们注意到以下几点:

    <input type="range" [(ngModel)]="value" (ngModelChange)="updateChanges()">
    
     <input type="range" [(ngModel)]="inputSliderValue (ngModelChange)="inputSliderValueChange.emit(inputSliderValue)">
    
    • 第一种方法允许您使用
      [(ngModel)]=“组件外部的PropertyName”
      ,就像组件是任何表单元素一样
    • 只有第一种方法允许您直接使用验证(对于表单)
    • 但是第一种方法比第二种方法需要更多的组件类内部编码
    • 第二种方法允许对属性使用双向绑定,语法为
      [(propertyNameInsideTheComponent)]=“propertyNameOutsideTheComponent”

    也可以这样做,当您创建一个双向绑定[()]时,您可以使用相同的名称将其绑定到一个函数+“change”(在我们的例子中是inputModel和inputModelChange),这样,当您触发inputModelChange.emit('updatedValue')时,ngModel将更新。您只需要在组件中声明一次即可

    应用程序输入.component.ts

    import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core';
    
    @Component({
      selector: 'app-input',
      template: `  <input type="text" [(ngModel)]="inputModel" (ngModelChange)="inputModelChange.emit(inputModel)"/>`,
      styleUrls: ['./app-input.component.scss']
    })
    export class AppInputComponent {
      @Input() inputModel: string;
      @Output() inputModelChange = new EventEmitter<string>();
    }
    
    从'@angular/core'导入{Component,OnInit,Output,Input,EventEmitter};
    @组成部分({
    选择器:“应用程序输入”,
    模板:``,
    样式URL:['./app-input.component.scss']
    })
    导出类AppInputComponent{
    @Input()inputModel:字符串;
    @Output()inputModelChange=neweventemitter();
    }
    
    app.component.html

    <app-input [(inputModel)]="externalValue"></app-input>
    

    如果您不关心通过模板模型中的
    [ngModel]
    或反应式表单中的
    [formControl]
    绑定变量,则可以使用

    否则:

  • NG\u VALUE\u访问器
    注入令牌添加到组件定义中:

    import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
    
    @Component({
       ...,
       providers: [
         {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => AppInputComponent),
            multi: true
         }
       ]
    })
    
  • 实现
    ControlValueAccessor
    接口:

    export class AppInputComponent implements ControlValueAccessor {
    
      writeValue(obj: any): void {
        // Step 3
      }
    
      registerOnChange(fn: any): void {
        this.onChange = fn;
      }
    
      registerOnTouched(fn: any): void {
        this.onTouched = fn;
      }
    
      setDisabledState?(isDisabled: boolean): void {
      }
    
      onChange: any = () => { };
    
      onTouched: any = () => { };
    
    }
    
  • 更改时管理

    private _value;
    
    public get value(){
      return this._value;
    }
    
    public set value(v){
      this._value = v;
      this.onChange(this._value);
      this.onTouched();
    }
    
    writeValue(obj: any): void {
      this._value = obj;
    }
    
    // Optional
    onSomeEventOccured(newValue){
      this.value = newValue;
    }
    

  • 现在您可以使用

    这可能是@Vikas Yep,有一个正在运行的演示,谢谢,看起来您还没有领会这个想法。传递值非常简单。问题是如何使用onlye[(ngModel)]返回更新值。我可以使用输出和E返回更新值