knockout.js - knockoutjs - ko visible binding not working
Texto mal escrito contexto (5)
Código:
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>
El problema está en el método removeUser. De forma predeterminada, si no enlace el contexto, esto == UserToDelete - no viewOl objeto objeto. Si agrego al constructor: this.removeUser = this.removeUser.bind(this); (manually enforce context)
this.removeUser = this.removeUser.bind(this); (manually enforce context)
, entonces el contexto es como se necesita este == viewmodel, pero luego TypeScript se queja por "No se puede convertir la función a (usuario: Usuario) => void requiere una firma de llamada, pero la función carece de una."
No estoy familiarizado con Ko así que tal vez haya una mejor manera de resolver el cambio de contexto, pero el error del compilador mecanografiado es causado por ''bind'' return type ''Function'' que no es compatible con el tipo de ''removeUser''. Debería poder resolver esto al convertir la función devuelta en la firma de tipo original de la siguiente manera:
this.removeUser = <(user: User) => void> this.removeUser.bind(this);
Bueno, tuve el mismo problema por eso se me ocurrió la siguiente clase base para solucionar mi problema
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);
}
}
}
}
lo que hace es repetir todos los miembros de su clase y si un método comienza con On, creará un nuevo método sin On que llamará al método original con el contexto correcto.
No es que $.proxy
sea una llamada jquery, por lo que se necesita jquery para que esto funcione.
Bueno, la solución más simple y lo que normalmente hago con js mecanografiado y nocaut es que no declaro funciones llamadas de knockout en el prototipo sino en el constructor. Entonces, lo haría así:
export class ViewModel {
public users: knockout.koObservableArrayBase;
removeUser:(user: User) => void;
constructor () {
this.users = ko.observableArray([]);
this.removeUser = (user:User) => {
this.users.remove(user);
}
}
}
Tuve el mismo problema. Para obtener el contexto correcto, puede usar los parámetros que pasan mediante el enlace de clic. El enlace de enlace pasa 2 parámetros, es decir, el usuario y el evento jquery del clic.
Si toma el evento jquery y utiliza la función ko.contextFor (), puede obtener el contexto correcto.
Su función sería algo así como:
removeUser(user: User, clickEvent: any): void {
var self = ko.contextFor(clickEvent.srcElement).$root;
self.users.remove(user);
}
Una alternativa es cambiar el enlace de clic para usar la función de enlace de JavaScript para forzar el valor de this
para ser su modelo de vista: data-bind="click: $root.MyFunc.bind($root)"
.
Tenga en cuenta que $data
y el objeto de event
click se pasarán como argumentos a MyFunc
desde Knockout como se describe en la especificación de enlace de clic . Si necesita anular los argumentos que se pasan a MyFunc
, simplemente MyFunc
a la función de enlace después de $root
como lo hace: .bind($root, param1, param2)
. Técnicamente, estos argumentos serán antepuestos a los argumentos proporcionados por Knockout, dando argumentos [param1, param2, data, event]
.