2 votes

knockoutjs sans conteneur si autour de <tr> et </tr>.

J'essaie de construire un tableau comme suit, mais j'obtiens "Error : Cannot find closing comment tag to match : ko if : cellIsStartOfRow".

Est-ce que je m'y prends mal ?

<table>
    <tbody data-bind="foreach: MyDocs">
        <!-- ko if: cellIsStartOfRow --> 
            <tr class="docsRow">
        <!-- /ko -->  
                <td>

                      <!-- There is more databinding in here - a div containing a textarea and also containing a hyperlink surrounding an image.  I think the contents are irrelevant to my question, but I can post if someone disagrees.-->  

                </td> 

        <!-- ko if: cellIsEndOfRow --> 
            </ tr>
        <!-- /ko --> 

   </tbody>
</table>

Voici le JS pour le viewmodel. Le contenu de la td ci-dessus est quelque peu simplifié, car j'ai pensé que ce qu'il contenait n'avait pas beaucoup d'importance. J'appelle les fonctions à partir d'autres éléments de ma page. Le viewmodel lui-même est assigné à une variable qui est déclarée sur la page.

Type.registerNamespace("HpDocs");

HpDocs.DocsVM = function (data) {
    ko.mapping.fromJS(data, {}, this);

    // add additional properties to each document for presentation
    // purposes
    for (i = 0; i < this.MyDocs().length; i++) {
        var myDoc = this.MyDocs()[i];
        myDoc.docObjectId = "docObject" + myDoc.Id();
        myDoc.textareaId = "ucHpDocs" + "_txta";

        if (i % 5 == 0) {
            myDoc.cellIsStartOfRow = true;
            myDoc.cellIsEndOfRow = false;
        } else if (i % 5 == 5) {
            myDoc.cellIsStartOfRow = false;
            myDoc.cellIsEndOfRow = true;
        } else {
            myDoc.cellIsStartOfRow = false;
            myDoc.cellIsEndOfRow = false;
        }
    }
};

HpDocs.DocsVM.prototype = {
//    cellIsStartOfRow: function(){
//        return true;
//    },
    getDocs: function (filter) {
        var self = this;
        $.ajax({
            url: getMethodUrl("GetDocs"),
            data: "{'filter': " + filter + "}",
            success: function (response) {
                ko.mapping.fromJS(response.d, {}, self.MyDocs);
            }
        })
    }
};

HpDocs.dbGetDocs = function (filter) {
    $.ajax({
        url: getMethodUrl("DbGetDocs"),
        data: "{'filter': " + filter + "}",
        success: function (response) {

            myDocsViewModel = new HpDocs.DocsVM({
                MyDocs: ko.mapping.fromJS(response.d)
            });

            var bindingScope = $("#divMyDocs")[0];
            ko.applyBindings(myDocsViewModel, bindingScope);

            $(".DocsUpdateProgress").addClass("invisible");
        }
    })
};

HpDocs.getPreferredTab = function () {
    var tabPref = $("[id$='hidDocTabPreference']").html();
    return tabPref;
};

HpDocs.showProgress = function () {
    $(".DocsUpdateProgress").removeClass("invisible");
};
HpDocs.hideProgress = function () {
    $(".DocsUpdateProgress").addClass("invisible");
};

//register the class
HpDocs.DocsVM.registerClass('HpDocs.DocsVM', null, Sys.IDisposable);

// notify ajax that the script is now loaded.
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

RÉPONSE

J'ai remanié mon modèle : au lieu que MyDocs contienne une liste d'objets, il contient maintenant une propriété appelée Rows qui contient à son tour une propriété appelée Documents. Il me suffit alors de faire ce qui suit :

<table id="tblMyDocs">
                <tbody data-bind="foreach:  MyDocs.Rows">

                        <tr data-bind="foreach: Documents">
                                  <td>
                                          <!-- in here i present each document by databinding to the Model's properties -->
                                  <td>
                        </tr>
                 </tbody>
</table>

et bien sûr le viewmodel est beaucoup plus facile, puisque le modèle est maintenant organisé en lignes :

HpDocs.DocsVM = function (data) {
    ko.mapping.fromJS(data, {}, this);
};

HpDocs.DocsVM.prototype = {
    getDocs: function (filter) {
        var self = this;
        $.ajax({
            url: getMethodUrl("GetDocs"),
            data: "{'filter': " + filter + "}",
            success: function (response) {
                ko.mapping.fromJS(response.d, {}, self.MyDocs);
            }
        })
    }
};

HpDocs.dbGetDocs = function (filter) {
    $.ajax({
        url: getMethodUrl("DbGetDocs"),
        data: "{'filter': " + filter + "}",
        success: function (response) {

            myDocsViewModel = new HpDocs.DocsVM({
                MyDocs: ko.mapping.fromJS(response.d)
            });

            var bindingScope = $("#divMyDocs")[0];
            ko.applyBindings(myDocsViewModel, bindingScope);

            HpDocs.hideProgress();
        }
    })
};

2voto

Jason More Points 2745

Au lieu d'ajouter une logique de formatage à votre js comme ci-dessous :

// add additional properties to each document for presentation
    // purposes
    for (i = 0; i < this.MyDocs().length; i++) {
        var myDoc = this.MyDocs()[i];
        myDoc.docObjectId = "docObject" + myDoc.Id();
        myDoc.textareaId = "ucHpDocs" + "_txta";

        if (i % 5 == 0) {
            myDoc.cellIsStartOfRow = true;
            myDoc.cellIsEndOfRow = false;
        } else if (i % 5 == 5) {
            myDoc.cellIsStartOfRow = false;
            myDoc.cellIsEndOfRow = true;
        } else {
            myDoc.cellIsStartOfRow = false;
            myDoc.cellIsEndOfRow = false;
        }

Je suggérerais de créer un modèle de vue distinct pour chaque ligne de données. Comme vous n'avez pas fourni de données json, je n'ai pas pu résoudre le problème à 100%, mais j'espère que cela vous mettra sur la bonne voie. Voici le jsfiddle sur lequel j'ai travaillé : http://jsfiddle.net/JasonMore/GcSAn/2/

Voir

<table>
    <tbody data-bind="foreach: someArray">
            <tr class="docsRow" data-bind="foreach:docRows">
                <td>
                    <div data-bind="attr:  {id: objectId}">
                       <a data-bind="attr: {href: someUrl}">
                          <img data-bind="attr: {src: IconPath, alt: Tooltip}"/>
                       </a> 
                       <br/>
                       <textarea runat="server" readonly="readonly" data-bind="html: DisplayName"></textarea>

                    </div>
                </td> 
            </ tr>

   </tbody>
</table>​​​​​

Javascript

HpDocs.RowVM = function(data) {
    ko.mapping.fromJS(data, {}, this);

}

HpDocs.DocsVM = function(data) {
    ko.mapping.fromJS(data, {}, this);

    this.docRows = ko.observableArray();

    // add additional properties to each document for presentation
    // purposes
    for (i = 0; i < this.MyDocs().length; i++) {
        var myDoc = this.MyDocs()[i];
        myDoc.docObjectId = "docObject" + myDoc.Id();
        myDoc.textareaId = "ucHpDocs" + "_txta";

        if (i % 5 == 0) {
            // create new RowVM and start adding DocsVM to it
        } else if (i % 5 == 5) {
            // push the RowVM to this.docRows populated with cells
        } else {
            // add the myDoc to the current RowVM you are working with
        }
    }
};

MISE À JOUR - Liens vers un exposé sur la façon de créer un mvvm approprié.

Diapositives et exemples : http://bit.ly/FamilyFeudSlides

Code : https://github.com/jasonmore/familyfeud

2voto

Jake K Points 21

Le problème est là :

<!-- ko if: cellIsStartOfRow --> 
   <tr class="docsRow">
<!-- /ko -->  

vous devez avoir des balises d'ouverture et de fermeture à l'intérieur du if, donc

<!-- ko if: cellIsStartOfRow --> 
   <tr class="docsRow">
   ... 
   </tr>
<!-- /ko -->

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X