Domanda

Sto usando knockout (ko) nel mio progetto MVC. Creo un modello MVC (per una griglia) sul server e passalo alla vista. Sulla vista è serializzata e convertita in un modello KO (usando KO.Mapping) che a sua volta viene utilizzato per il rilegatura. Quel rilegatura viene quindi utilizzato in HTML per la creazione della griglia.

Ecco come appare il mio modello di griglia MVC a che a sua volta viene convertito in corrispondente modello KO da KO.Mapping:

public class GridModel
    {
        /// <summary>
        /// Grid body for the grid.
        /// </summary>
        public GridBodyModel GridBodyModel { get; set; }

        /// <summary>
        /// Grid context.
        /// </summary>
        public GridContext GridContext { get; set; }

        /// <summary>
        /// Grid header for the grid.
        /// </summary>
        public GridHeaderModel GridHeader { get; set; }
    }

public class GridBodyModel
    {
        /// <summary>
        /// List of grid body rows.
        /// </summary>
        public IList<GridRowModel> Rows { get; set; }
    }


public class GridContext
    {
        /// <summary>
        /// Total number of pages. Read-only.
        /// </summary>
        public int TotalPages{ get; set; }
    }

public class GridHeaderModel
    {
        /// <summary>
        /// List of grid header cells.
        /// </summary>
        public IList<GridHeaderCellModel> Cells { get; set; }
    }
.

Poiché è chiaro, la classe principale della classe Gridmodel è fatta di classi seguenti che sono presenti come proprietà:

GridBodyModel: ha un elenco di righe da rendering nel corpo della griglia.

GridContext: ha un numero totale di pagine come proprietà. Ha altre proprietà, ma questo è fuori portata di questa discussione.

GridHeaderModel: ha un elenco di celle che devono essere visualizzate in intestazione della griglia.

Allora ho questo script che eseguirà sul caricamento della pagina fresca.

$(document).ready(function () {
        // Apply Knockout view model bindings when document is in ready state.
        ko.applyBindings(Global_GridKOModel, document.getElementById("gridMainContainer"));
    });

// Serialize the server model object. It will be used to create observable model.
Global_GridKOModel = ko.mapping.fromJS (<%= DataFormatter.SerializeToJson(Model) %>);
.

Global_Gridkomodel è la variabile JavaScript globale. Modello è il modello Grid MVC proveniente dal server.

Un utente può eseguire ulteriori ricerche sulla pagina di nuovo. Gestisco questo pubblicando nuovi criteri di ricerca tramite Ajax. Su questo post è stato creato un nuovo modello MVC e viene inviato come risposta Ajax. Questo nuovo modello MVC viene quindi utilizzato per aggiornare Global_Gridkomodel utilizzando KO.Mapping che a sua volta aggiorna la griglia (con nuovi dati) che è stata costruita in precedenza sul caricamento della pagina fresca. Questo è il modo in cui lo sto facendo.

$.ajax({
        url: destUrl,
        data: dataToSend
        success: function (result) {
            ko.mapping.fromJS(result, Global_GridKOModel);
        },
        error: function (request, textStatus, errorThrown) {
            alert(request.statusText);
        }
    });
.

Tutto funziona bene tranne nel seguente scenario.

Viene restituito una richiesta Ajax per il quale non viene restituito alcun risultato I.e. GridBodyModel e GridHeaderModel è NULL nel modello GridModel . Quella griglia di tempo giustamente mostra che nessun record è stato trovato. Questo è corretto. Questo succede dal seguente legame HTML.

<!-- When no record is found. -->
<div data-bind="ifnot: GridContext.GridPager.TotalPages() > 0">
    No record(s) were found.
</div>

<!-- This is actual grid table container. This is binded when records are found -->
<div data-bind="if: GridContext.TotalPages() > 0">

Grid construction happens here

</div>
.

Ora dopo questa se è stata restituita un'altra richiesta AJAX, ma questa volta vengono restituiti i record (ho controllato la risposta con Firebug e viene confermata che i record sono effettivamente restituiti). Questa costruzione la costruzione della griglia avviene in cui sono accessibili vari array osservabili. Ad esempio, per costruire il cercapersone per la griglia che segue è un pezzo di legame HTML che ho scritto.

<td data-bind="attr:{colspan: GridHeader.Cells().length }">
.

Questa volta KO getta il seguente errore che può essere visto in Firebug.

incapace di analizzare i binding. Messaggio: TypeError: Gridheader.Cells non è una funzione; Valore Bindings: Attr: {Colspan: Gridheader.Cells (). Lunghezza}

Funziona bene così a lungo sono restituiti record, ma si rompe dopo che nessun record è restituito come spiegato sopra. Si prega di notare Gridheader era nullo nella risposta precedente quando non sono stati restituiti record. Annuido qualcosa di pescante in ko.mapping. Penso che ci sia un problema durante la mappatura dell'array osservabile.

Allora, cos'è che non sto facendo bene? Chiunque per favore?

Non esitate a chiedere chiarimenti se non ho menzionato le cose chiaramente.

Grazie in anticipo.

È stato utile?

Soluzione

Il motivo effettivo del comportamento è che originariamente Gridheader è oggetto JavaScript, ma quando la tua chiamata di ritorno mappatura con NULL per la proprietà di Gridheader, diventerà osservabile con il valore nullo e su tutti gli aggiornamenti futuri sarà comunque osservabile. .

Le soluzioni alternative sono (Scegli una):

    .
  1. Non restituire valori nulli per i modelli per bambini (invece restituire gli oggetti vuoti) - Penso che sia preferito nel modo
  2. o - Prima di chiamare la mappa, eseguire Global_gridkomodel.gridheader= null; (Questo garantirà che dopo l'aggiornamento Gridheader non sarà osservabile)
  3. o - Dopo la mappatura, chiamata Global_gridkomodel.gridheader= ko.unwapobservable (global_gridkomodel.gridheader);

    Full Spiegazione del comportamento che hai è nel codice qui sotto (copia su JSFIDDLE - http:// jsfiddle. NET / NICKOLSKY / ZRUL / 9 / )

    console.log('step1');
    var vm = ko.mapping.fromJS({ body: { children: [ 1, 2, 3]} });
    console.log(vm.body.children()[1]); //prints 2
    
    console.log('step2');
    ko.mapping.fromJS({ body: { children: [ 4, 5, 6]} }, vm);
    console.log(vm.body.children()[1]); //prints 5
    
    console.log('step3');
    //after next call, vm.body is no longer variable - it is now observable
    ko.mapping.fromJS({ body: null }, vm);
    console.log(vm.body); //prints observable
    console.log(vm.body()); //prints null
    
    console.log('step4');
    //and it will remain observable for next call
    ko.mapping.fromJS({ body: { children: [ 7, 8, 9]} }, vm);
    console.log(vm.body().children()[1]); //prints 8
    console.log(vm.body().children().length); //prints 3
    console.log(vm.body); //prints observable function body
    console.log(vm.body()); //prints object
    
    //workaround for null issue - we can reset it to be null instead of null observable
    //and it will get original behavior
    vm.body = null;
    console.log('step5');    
    ko.mapping.fromJS({ body: { children: [ 7, 8, 9]} }, vm);
    console.log(vm.body.children()[1]); //prints 8 - body is no longer observable again
    ​
    
    .

    Per me sembra un problema di progettazione del plugin della mappatura, non sono stato in grado di trovare un modo per personalizzare la mappatura per la mappatura per le proprietà di ViewModel per bambini per assicurarti che non diventeranno osservabili se sono nulle (la funzionalità "copia" farà tutto Contenuto interiore come non osservato, sfortunatamente).

Altri suggerimenti

L'ho capito la scorsa notte. In realtà questo era un errore molto semplice che stavo facendo. Stavo cercando di accedere a un array dopo averlo impostato su nulla. Lo spiegherò come.

Quando i risultati sono stati restituiti quel tempo GridHeadermodel e le cellule ilist in esso sono state definite I.e. Non erano null. Quella volta Ko.Mapping è stato in grado di convertire il modello e creare il modello e l'arrivo al suo interno. Ma quando è stata resa una richiesta Ajax in cui il risultato del Noo è stato restituito e GridHeaderModel era nullo, ovviamente le cellule ilist erano anche nulla. That Time Ko.Mapping ha fatto lo stesso, il modello KO che ha aggiornato, impostare anche GridHeaderModel a NULL e le cellule dell'array osservabile all'interno non erano presenti che è buono come NULL. Ora, quando ho fatto un'altra richiesta AJAX con alcuni record restituiti, il KO.Mapping ha provato ad aggiornare le celle di array osservabili che non esistevano (o sono state impostate su NULL) nel modello KO sul client, non è riuscito. Se invece di Ajax era un caricamento di pagine fresche, tutto avrebbe funzionato. Quindi la soluzione non è restituire alcuna enumerazione (quelle che verranno convertite in array osservabile) non inizializzate al client per l'aggiornamento del modello KO. Quindi quando nessun record doveva essere restituito, mi sono assicurato che GridHeaderModel non sia nullo e si è fatto anche in modo che le cellule ilist siano inizializzate anche se non ha contenuto alcun elemento. Questo ha risolto il problema.

Questo problema potrebbe essere esplosionato con il seguente esempio.

public class Demo
{
    public IList<string> DemoArray;
}

public class DemoUser
{
    public void UseDemo()
        {
            var demoInstance = new Demo();
            demoInstance.DemoArray.Add("First Element");
        }
}
.

Qui nel metodo UseDemo () abbiamo inizializzato la demo dell'istanza della classe, ma il demoray ilist rimane innizializzato. Quindi, quando proviamo ad accedervi l'eccezione del runtime verrà lanciata. Questo è ciò che stava succedendo nel mio caso. Nella prima risposta Ajax stavo impostando l'array osservabile su null I.e-Inizializzarlo e poi nella prossima risposta Ajax stavo cercando di accedervi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top