2017-04-09 10 views
1

我正在看看nativescript hello world typescript回購,我遇到了一些繁瑣的工作與nativescript的observables的實施。Nativescript類實現observables默認設置行爲

如果你看看如何定義view model,你可以看到它是一個簡單擴展Observable庫的類。每當你定義的屬性,一個setter方法 你手動需要調用super.notifyPropertyChange("propertyName", propertyValue);

恕我直言,這個過程是非常低效的,而且容易出錯,如果你有很多屬性視圖模型。

有沒有一種方法來自動執行此任務? (也許有一個基類告訴任何setter到notifyPropertyChange?) 如果不是,你是如何處理這個問題的? Observable機制還有其他的實現嗎?

回答

5

這是我一直在使用的幾個生產應用程序的內容:

import { Observable } from "data/observable"; 

export class ObservableModel extends Observable { 
    constructor() { 
     super(); 
    } 

    public get(propertyName: string) { 
     return this["_" + propertyName]; 
    } 

    public set(propertyName: string, value) { 
     if (this["_" + propertyName] === value) { 
      return; 
     } 

     this["_" + propertyName] = value; 
     this.refresh(propertyName); 
    } 

    public refresh(propertyName: string) { 
     super.notify({ 
      eventName: Observable.propertyChangeEvent, 
      propertyName, 
      object: this, 
      value: this["_" + propertyName], 
     }); 
    } 
} 

那麼你的模型看起來是這樣的:

export class LoginViewModel extends ObservableModel { 
    get userName(): string { return this.get("userName"); } 
    set userName(val: string) { this.set("userName", val); } 

    get password(): string { return this.get("password"); } 
    set password(val: string) { this.set("password", val); } 
} 

而當你需要與你剛纔使用的值工作:

const vm = new LoginViewModel(); 
vm.userName = "jdoe"; 
vm.password = "$3cr3T"; 

UPDATE 裝飾實現:

export function ObservableProperty() { 
    return (target: Observable, propertyKey: string) => { 
     Object.defineProperty(target, propertyKey, { 
      get: function() { 
       return this["_" + propertyKey]; 
      }, 
      set: function (value) { 
       if (this["_" + propertyKey] === value) { 
        return; 
       } 

       this["_" + propertyKey] = value; 
       this.notify({ 
        eventName: Observable.propertyChangeEvent, 
        propertyName: propertyKey, 
        object: this, 
        value, 
       }); 
      }, 
      enumerable: true, 
      configurable: true 
     }); 
    }; 
} 

型號:

export class LoginViewModel extends Observable { 
    @ObservableProperty() public userName: string; 
    @ObservableProperty() public password: string; 
} 
+0

不錯!謝謝:) –

+0

是否可以添加一個裝飾器來防止手動設置屬性的字符串值? –

+0

@AaronUllal看看更新後的回覆。不是裝飾專家,但我試過了,它的工作原理:) –

1

這的確是冗長且容易出錯。這是違反DRY的,應該避免。有很多方法可以用JavaScript完成這個乾淨的工作。

一種方法可能是使用裝飾器以通用方式自動連接所有樣板並保持模型類的清潔和聲明。

例如,我們可以創建以下功能

observed.ts

export default function<T extends Notifier<T, K>, K extends keyof T>(target: T, key: K) { 
    let storedValue = target[key]; 

    const get =() => storedValue; 

    const set = (value: T[K]) => { 
    if (storedValue !== value) { 
     storedValue = value; 
     target.notifyPropertyChange(key, storedValue); 
    } 
    }; 

    Object.defineProperty(target, key, { 
    get, 
    set, 
    enumerable: true, 
    configurable: false 
    }); 
} 

export interface Notifier<T, K extends keyof T> { 
    notifyPropertyChange(key: K, value: T[K]): void; 
} 

現在,我們可以用它來從模型本身刪除所有的樣板。我們甚至刪除了吸氣和安裝人員,並使用簡單的屬性

模型。TS

// Stub observable class to verify inheritance works correctly (as requested) 
class Observable { 
    notifyPropertyChange(key: string, value: {}) { 
    console.log(`from super: ${key} ===> ${value}`); 
    } 
} 

export class Model extends Observable { 

import observed from './observed'; 

export class Model extends Observable { 
    @observed name = 'Bob'; 

    @observed age = 38; 

    @observed birthdate = moment(); 

    notifyPropertyChange<K extends keyof this>(key: K, value: this[K]): void { 
    super.notifyPropertyChange(key, value); 
    console.log(`${key} ===> ${value}}`); 
    } 
} 

const model = new Model(); 

model.name = 'Rob'; 

model.name = 'Robert'; 

一些這種做法的好處是,

  • 這是相當枯燥

  • 我們比,如果我們定義的getter更加簡明易讀模型類和手動設置器

  • 我們的裝飾器通過要求類提供notifyPropertyChange方法,它會在正確的屬性鍵上調用。如果我們違反這個規定,TypeScript將發出編譯器錯誤

  • 用於存儲該值的實際變量是真正的私有。它只在裝飾者封閉的範圍內,除了通過吸氣者和設定者之外不能被訪問。這不是一個命名約定,它是真正的隱私,良好的老式JavaScript方式

  • 我們避免只爲代碼共享引入基類。這是我們可以寧願組成繼承
  • 我們獲得直列初始化的便利性和產生的類型推斷

這可以推廣到裝飾整個類,使它變得機。

+0

我喜歡這種方法!我會嘗試一下:)謝謝 –

+0

我才意識到,我有,我只是固定一個錯字。我測試了這一點,但後來重命名了一些東西以適合單行的stackoverflow格式並錯過了一個名稱。然而 –

+0

這種方法的問題是,因爲裝飾被上課的時候被宣佈之前調用,在notifyPropertyChange方法我不能叫超()。notifyPropertyChange,這將是希望的行爲 –