2016-03-28 26 views
15

我有一个自定义选择组件,它在您点击li项目时设置模型,但由于我每次更改模型时都手动调用this.modelChange.next(this.model),所以我很想避免这种混乱和可重复的操作。如何在每次模型角度2变化时调用函数?

所以我的问题是,如果有类似$scope.$watch的东西,我可以观察一个值是否发生变化,然后每次发生时调用this.modelChange.next(this.model)

我一直在阅读关于Observables,但我无法弄清楚这应该如何用于一个简单的值,因为我看到的所有示例都与外部api:s的异步请求。

当然,必须有一个更简单的方法来实现这一目标?

(不是说我不能使用ngModelChanges,因为我实际上没有使用输入)。

import {Component, Input, Output, EventEmitter, OnInit, OnChanges} from 'angular2/core'; 

@Component({ 
    selector: 'form-select', 
    templateUrl: './app/assets/scripts/modules/form-controls/form-select/form-select.component.html', 
    styleUrls: ['./app/assets/scripts/modules/form-controls/form-select/form-select.component.css'], 
    inputs: [ 
    'options', 
    'callback', 
    'model', 
    'label' 
    ] 
}) 

export class FormSelectComponent implements OnInit, OnChanges { 
    @Input() model: any; 
    @Output() modelChange: EventEmitter = new EventEmitter(); 

    public isOpen: boolean = false; 

    ngOnInit() { 

    if (!this.model) { 
     this.model = {}; 
    } 

    for (var option of this.options) { 

     if (option.model == (this.model.model || this.model)) { 
     this.model = option; 

     } 
    } 
    } 

    ngOnChanges(changes: {[model: any]: SimpleChange}) { 
    console.log(changes); 
    this.modelChange.next(changes['model'].currentValue); 
    } 

    toggle() { 
    this.isOpen = !this.isOpen; 
    } 

    close() { 
    this.isOpen = false; 
    } 

    select(option, callback) { 
    this.model = option; 
    this.close(); 

    callback ? callback() : false; 
    } 

    isSelected(option) { 
    return option.model === this.model.model; 
    } 
} 

编辑:我尝试使用ngOnChanges(见上更新的代码),但它只能在初始化运行一次,然后在没有检测的变化。有什么不对?

回答

18

所以我的问题是,如果有类似$范围的东西$看我在哪里可以看,如果输入属性model的值更改。

如果model是一个JavaScript基本类型(数字,字符串,布尔值),那么你就可以实现ngOnChanges()要通知符变化。请参阅cookbook examplelifecycle doc, OnChanges section
另一种选择是使用setter和getter。见cookbook example

如果model是一个JavaScript引用类型(数组,对象,日期等),那么你是怎样判断的变化取决于如何模型的变化:

  • 如果参考模型的变化(即,您指定一个新的数组,或一个新的对象等),您可以实现ngOnChanges()以通知更改,就像原始类型一样。然而,如果模型引用没有改变,但模型的某些属性发生了变化(例如,数组项的值发生了变化,或者数组项被添加或删除,或者对象属性值发生变化),但是,如果模型引用不发生变化,您可以执行ngDoCheck()来实现您自己的更改检测逻辑。
    lifecycle doc, DoCheck section
+0

Set/get不起作用它只是抛出一大堆错误,ngOnChanges不起作用,因为我改变了组件内部的值,然后用两种方式将它绑定到父组件。 ngDoCheck()似乎是过度杀伤,因为我只需要知道它是否发生了变化,我不需要任何特定的逻辑。我真正喜欢的是使用观察者,但我正在为如何实施而失去理智。你能告诉我如何与观察员达成这个目标吗?使用我的代码,不是一些与我的用例完全不同的随机示例。我会很感激它像疯了一样。 – Chrillewoodz

+0

关于ngDoCheck(),Angular不能神奇地知道我们的ReferenceTypes的结构,所以如果我们必须为他们编写我们自己的变化检测逻辑,这并不过分。 (这在我引用的生命周期文档中讨论过。)由于'model'是一个输入属性,我将使用ngDoCheck()而不是observable。你有一个简单的蹦床,只是演示非工作片? –

+0

“由于model是一个输入属性,所以我会使用ngDoCheck()而不是observable。”为什么是这样?你应该为http请求以外的其他应用程序使用observables吗?通过检查以前的模型,我得到它与doCheck一起工作,或者它最终成为一个无限循环。 – Chrillewoodz

0

您可以做一个model的getter/setter方法或通过添加ngOnChanges(changes) {}方法被称为每一个@Input()值更改后的时间实现OnChanges

从文档的ngOnChanges()例如(上面链接):

@Component({ 
    selector: 'my-cmp', 
    template: `<p>myProp = {{myProp}}</p>` 
}) 
class MyComponent implements OnChanges { 
    @Input() myProp: any; 
    ngOnChanges(changes: {[propName: string]: SimpleChange}) { 
    console.log('ngOnChanges - myProp = ' + changes['myProp'].currentValue); 
    } 
} 
@Component({ 
    selector: 'app', 
    template: ` 
    <button (click)="value = value + 1">Change MyComponent</button> 
    <my-cmp [my-prop]="value"></my-cmp>`, 
    directives: [MyComponent] 
}) 
export class App { 
    value = 0; 
} 
bootstrap(App).catch(err => console.error(err)); 

更新

如果的model变化的内部状态,但不是model本身(不同model实例)然后改变检测不承认它。您需要实现自己的机制来通知感兴趣的代码,例如在model中使用Observable,它发出组件可以订阅的更改事件。

此外,当model通过数据绑定(当someFieldInParent<my-comp [model]="someFieldInParent">已经改变和角传入MyComponent新值model

return option.model === this.model.model;改变ngOnChanges()仅称为不引起ngOnChanges()被调用。对于这工作的getter/setter方法是一种更适合

+0

好吧,我会看ngOnChanges,但请包括一些示例代码,如果你还想要你的答案以获得接受;) – Chrillewoodz

+0

完成。 。 。 。 。 。 –

+0

检查更新后的问题,看起来似乎无法在首次执行后检测到任何问题。 – Chrillewoodz

2

如果选择自定义组件在内部使用的表单输入(S),我会充分利用它/他们ngModelChange事件:

<select [ngModel]="..." (ngModelUpdate)="triggerUpdate($event)">…</select> 

或valueChanges可观察到的相应控件(如果有的话)。在模板:

<select [ngFormControl]="myForm.controls.selectCtrl">…</select> 

在组件:

myForm.controls.selectCtrl.valueChanges.subscribe(newValue => { 
    (...) 
}); 
+0

这个是我为什么要去实际的表单元素,但它不适用于我使用ul/li元素的自定义选择,所以我认为一个可观察的解决方案就是要走的路。我可以理解他们是如何工作的,哈哈。 – Chrillewoodz

+0

只是想一想:为什么不用你选择的组件之一调用emit方法? ;-) –

+0

因为它不是模型改变的唯一地方,它可以改变3种不同的方式。这就是我最初的做法,但后来认识到,模型在首次接收现有值时也必须更新,并且如果没有值并且模型必须设置为空对象。 – Chrillewoodz

相关问题