2012-10-07 23 views
7

Kod:Typescript niewłaściwy kontekst tego

export class ViewModel { 
     public users: knockout.koObservableArrayBase; 

     constructor() { 
      this.users = ko.observableArray([]); 
      this.removeUser = this.removeUser.bind(this);//<-- Here compiller shows error 
     } 

     removeUser(user: User): void { 
      this.users.remove(user); 
     } 
} 

HTML:

<table> 
    <thead> 
     <tr> 
      <th>Name</th> 
      <th>Surname</th> 
     </tr> 
    </thead> 
    <tbody data-bind="foreach: users"> 
     <tr> 
      <td><a href="#" data-bind="click: $root.removeUser">Remove</a></td> 
      <td data-bind="text: name"></td> 
      <td data-bind="text: surname"></td> 
     </tr> 
    </tbody> 
</table> 

Problem jest w metodzie RemoveUser. Domyślnie, jeśli nie wiążę kontekstu, to == UserToDelete - nie viewModel obiektu. Jeśli dodaję do konstruktora: this.removeUser = this.removeUser.bind(this); (manually enforce context), kontekst jest w razie potrzeby to == viewmodel, ale następnie TypeScript narzeka na "Nie można przekonwertować funkcji na (użytkownik: użytkownik) => void wymaga sygnatur połączeń, ale funkcja nie ma jednego."

+0

Jeśli nie masz nic przeciwko niechlujnemu HTML, jest to alternatywa: Remove

Odpowiedz

5

Nie jestem zaznajomiony z ko, więc być może istnieje lepszy sposób na rozwiązanie przełączania kontekstu, ale błąd kompilatora maszynopisu jest spowodowany przez "zwracanie" typu "funkcja", co jest niezgodne z typem "removeUser" . Powinieneś być w stanie rozwiązać ten problem poprzez odlewanie funkcję zwrócony w oryginalnym podpisem typu następująco:

this.removeUser = <(user: User) => void> this.removeUser.bind(this); 
2

Cóż miałem ten sam problem, to dlaczego ja przyszedłem z poniższej klasy bazowej, aby rozwiązać mój problem

export class ViewModelBase { 
    private prefix: string = 'On'; 

    public Initialize() { 
     for (var methodName in this) { 
      var fn = this[methodName]; 
      var newMethodName = methodName.substr(this.prefix.length); 
      if (typeof fn === 'function' && methodName.indexOf(this.prefix) == 0 && this[newMethodName] == undefined) { 
       this[newMethodName] = $.proxy(fn, this); 
      } 
     } 
    } 
} 

to, co robi, to zapętla wszystkich członków klasy i jeśli metoda zaczyna się od On, utworzy nową metodę bez On, która wywoła oryginalną metodę z odpowiednim kontekstem.

To nie jest $.proxy jest wywołanie jquery więc jquery jest potrzebne do tego działa.

1

Cóż, najprostszym rozwiązaniem i co zwykle robię z maszynopisem i nokautem jest to, że nie deklaruję funkcji wywołanych z nokautu na prototypie, ale na konstruktorze. Tak więc, zrobiłbym to tak:

export class ViewModel { 
     public users: knockout.koObservableArrayBase; 
     removeUser:(user: User) => void; 

     constructor() { 
      this.users = ko.observableArray([]); 
      this.removeUser = (user:User) => { 
       this.users.remove(user); 
      } 
     } 
} 
0

Wpadłem na ten sam problem. Aby uzyskać odpowiedni kontekst, możesz użyć parametrów przekazywanych przez klikanie. Po kliknięciu przycisku przechodzą 2 parametry, tj. Użytkownik i zdarzenie jquery kliknięcia.

Jeśli wykonasz zdarzenie jquery, a następnie użyjesz funkcji ko.contextFor(), możesz uzyskać odpowiedni kontekst.

Twoja funkcja będzie wyglądać następująco:

removeUser(user: User, clickEvent: any): void { 
    var self = ko.contextFor(clickEvent.srcElement).$root; 
    self.users.remove(user); 
} 
2

Alternatywą jest zmiana kliknięcie wiązania używać bind funkcji JavaScript, aby wymusić wartość this być model widok: data-bind="click: $root.MyFunc.bind($root)".

Zauważ, że $data a obiekt kliknięcie event będą nadal przekazywane jako argumenty do MyFunc z Knockout jak opisano w specyfikacji click binding. Jeśli chcesz przesłonić argumenty przekazywane do MyFunc, po prostu prześlij je do funkcji wiązania po $root, tak jak: .bind($root, param1, param2). Technicznie, te argumenty będą poprzedzone z argumentami dostarczanymi przez Knockout, podając argumenty: [param1, param2, data, event].

Powiązane problemy