KnockoutJS: aggiunta di proprietà e funzioni osservabili agli oggetti in un ObservableArray generato dalla mappatura
-
28-10-2019 - |
Domanda
Sono nuovo su KnockoutJS e sono bloccato nel tentativo di aggiungere ulteriori proprietà e metodi agli oggetti generati nel ko.observableArray()
come creato dal plug-in mapping
.
Ecco dove sto andando:
- Ho un array JSON di
Users
- Ho creato
ko.observableArray()
con il plug-in di mappatura - Ho un modello che crea una riga di tabella per ogni
User
, finora tutto bene: o)
Ecco cosa sto cercando di fare:
Ogni User
ha una proprietà chiamata 'IsActive'
: vorrei generare un evento click su un metodo su ogni oggetto data-bind
che attiva questa proprietà User
.
Questa domanda sembrava promettente , ma a me sembra una duplicazione non necessaria dover dichiarare l'intero modello di visualizzazione in JS (a meno che non sia così che devo farlo!) - è possibile estendere semplicemente l'oggetto generato?
Ecco il codice: http://jsfiddle.net/yZkSf/2/ (non funziona ancora con JS fiddle, ma continuerò a giocarci e aggiornerò questo collegamento quando lo farò funzionare).
Grazie per il tuo aiuto
Soluzione
Ci sono diverse opzioni che potresti considerare.
-Uno è utilizzare il create
callback per controllare come il tuo "utente "gli oggetti vengono creati. Puoi definire tu stesso gli osservabili e aggiungere funzionalità extra o chiamare il plugin di mappatura sul singolo oggetto utente e quindi aggiungere funzionalità extra.
Potrebbe essere qualcosa del tipo: http://jsfiddle.net/rniemeyer/fkVaK/
-Altrimenti, puoi posizionare la funzione "toggle" sul tuo viewModel e poi passarvi l'oggetto "user".
Un bel modo con 1.3, è usare ko.dataFor
insieme a qualcosa come la funzionalità di delega degli eventi live / delegate / on di jQuery. Sarebbe come: http://jsfiddle.net/rniemeyer/FkjNr/
//unobtrusive event handler
$(".toggle").live("click", function() {
var user = ko.dataFor(this);
if (user) {
viewModel.toggleIsActive(user);
}
});
Se non desideri utilizzare la delega degli eventi, puoi passare l'elemento direttamente utilizzando una funzione anonima come: http://jsfiddle.net/rniemeyer/GpQtN/
MODIFICA: a partire dalla 2.0, i dati correnti vengono automaticamente passati al gestore quando si utilizzano associazioni di clic / eventi, quindi puoi semplicemente fare:
<a href="#" data-bind="click: $root.toggleIsActive"><span data-bind="text: IsActive"></span></a>
Altri suggerimenti
Questo è quello che mi è venuto in mente usando sia la tua risposta che quella di Ryan ... sembra funzionare.Per favore lascia un feedback, dato che sono nuovo di Knockout e sono curioso di sapere se questo è un buon approccio.
JS:
$(function() {
$.get("users/getUsers", function(r){
var vm = ko.mapping.fromJS(r, {
users: {
create: function(user){
var methods = {
toggleIsActive: function(u){u.IsActive(!u.IsActive());},
foo: function(u){console.log(u);},
bar: function(u){/*whatever*/},
}
return $.extend(ko.mapping.fromJS(user.data), methods);
}
}
});
ko.applyBindings(vm);
}, 'json');
});
DOM:
<!-- ko foreach: users -->
<a href="#" data-bind="click: toggleIsActive"><span data-bind="text: IsActive"></span></a>
<!-- /ko -->
Ho trovato un modo per farlo, ma significa scorrere gli oggetti generati nell'array una volta che sono stati creati .. Preferirei un modo per ottenere lo stesso risultato senza il ciclo aggiuntivo ..
EDIT: Come suggerisce RP Niemeyer nella sua risposta! ; o)
Ad ogni modo, un modo per aggiungere proprietà a un oggetto esistente è utilizzare jQuery extent () per combinare gli oggetti.
Per prima cosa, dichiara le proprietà e le funzioni extra in un nuovo oggetto:
var userModel = {
toggleIsActive: function() {
console.log('toggleIsActive called: before: ' + this.IsActive());
this.IsActive(!this.IsActive());
// todo: save!
console.log('toggleIsActive called: after: ' + this.IsActive());
}
}
Quindi, dopo la chiamata ko.mapping.fromJS()
, ma prima della chiamata ko.applyBindings()
, scorrere gli oggetti nell'array generato ed estenderli:
viewModel.users = ko.mapping.fromJSON(/* get JSON */);
for (var i = 0; i < viewModel.users().length; i++) {
$.extend(viewModel.users()[i], userModel);
}
ko.applyBindings(viewModel);