2017-03-18 8 views
0

Ich habe ein JSON-Array, das Elemente in einer foreach-Datenbank erstellt hat. Dann behalte ich das ausgewählte Objekt in diesem Array, so dass ich unabhängige Schaltflächen "Änderungen speichern" für jedes Objekt in diesem Array haben kann. All das funktioniert (primarycontactname zum Beispiel) mit Ausnahme der Bindung für die Checkboxen.Knockout foreach Array Checkboxen werden nicht visuell aktualisiert

<div class="container span8" data-bind="foreach: locationssubscribed"> 
    <div class="well span3" data-bind="click: $parent.selectedLocationSubscribed"> 
    <input type="text" class="span3" data-bind="value: primarycontactname" placeholder="Contact Name.." /> 
    <br />  
    <div class="checkbox" data-bind="visible: (vendorbringinggifts() === 0 || vendorbringinggifts() === vendorid())"> 
     <input id="chkGiftsAreBeingBrought" type="checkbox" data-bind="checked: giftsarebeingbrought" /> 
    </div> 
    <button data-bind="click: $root.saveVendorToLocation, enable: needsave, text: needsave() ? 'Save Location Changes' : 'No Changes to Save', css: { 'btn-primary': needsave }" class="btn">Save Location Changes</button> 
    </div> 
</div 

Das Kontrollkästchen Last auf dem giftsarebeingbrought beobachtbaren in jedem Array-Objekt automatisch korrekt, aber wenn Sie das Kontrollkästchen die Sichtkontrolle wechselt nicht klicken. Mit Hilfe des Debuggers kann ich sehen, dass die beobachtbaren Geschenke im ursprünglichen Array und im selectedLocationSubscribed auf den ersten Klick umgeschaltet werden, aber nicht bei nachfolgenden Klicks wieder umschalten und das visuelle Kontrollkästchen ändert sich nach der ersten Bindung nie.

{ 
    "locationssubscribed": [ 
    { 
     "vendortolocationid": 10, 
     "primarycontactname": "Fake Name1", 
     "vendorbringinggifts": 0, 
     "giftsarebeingbrought": false, 
     "needsave": false 
    }, 
    { 
     "vendortolocationid": 11, 
     "primarycontactname": "Fake Name2", 
     "vendorbringinggifts": 0, 
     "giftsarebeingbrought": false, 
     "needsave": false 
    }, 
    { 
     "vendortolocationid": 12, 
     "primarycontactname": "Fake Name3", 
     "vendorbringinggifts": 0, 
     "giftsarebeingbrought": false, 
     "needsave": false 
    }, 
    { 
     "vendortolocationid": 13, 
     "primarycontactname": "Fake Name4", 
     "vendorbringinggifts": 0, 
     "giftsarebeingbrought": false, 
     "needsave": false 
    } 
    ], 
    "selectedLocationSubscribed": { 
    "vendortolocationid": 12, 
    "primarycontactname": "Fake Name1", 
    "vendorbringinggifts": 0, 
    "giftsarebeingbrought": true, 
    "needsave": true 
    } 
} 



function VendorToLocation(vtl) { 
    this.vendortolocationid = ko.observable(vtl.VendorToLocationID); 
    this.primarycontactname = ko.observable(vtl.PrimaryContactName); 
    this.vendorbringinggifts = ko.observable(vtl.VendorBringingGifts); 
    this.giftsarebeingbrought = ko.observable(vtl.GiftsAreBeingBrought); 
    this.needsave = ko.observable(false); 
} 

function VendorViewModel() { 
    var self = this; 
     self.locationssubscribed = ko.observableArray(); 
    self.selectedLocationSubscribed = ko.observable(); 
    self.selectedLocationSubscribed.subscribe(function (ftl) { 
    if (ftl !== null) { 
     ftl.needsave(true); 
    } 
    }); 

    self.getLocationsAvailable = function (vendorID) { 
    self.locationsavailable.removeAll(); 
    $.ajax($("#GetLocationsAvailableUrl").val(), { 
     data: '{ "vendorID":' + vendorID + '}', 
     async: false, 
     success: function (allData) { 
     self.locationsavailable($.map(allData, function (item) { return new LocationsAvailable(item) })); 
     } 
    }); 
    } 

    self.getLocationSubscription = function (vendorID) { 
    self.locationssubscribed.removeAll(); 
    $.ajax($("#GetLocationSubscriptionUrl").val(), { 
     data: '{ "vendorID":' + vendorID + '}', 
     success: function (allData) { 
     self.locationssubscribed($.map(allData, function (item) { return new VendorToLocation(item) })); 
     } 
    }); 
    } 


    self.saveVendorToLocation = function() { 
    var url = $("#updateVendorToLocationUrl").val(); 
    var vendorid = self.selectedVendor().vendorid(); 
    var selectedLoc = self.selectedLocationSubscribed(); 
    $.ajax(url, { 
     data: '{ "vtl" : ' + ko.toJSON(selectedLoc) + '}', 
     success: function (result) { 
     if (result === false) { 
      toastr.error("ERROR!: Either you or a competing vendor has chosen this location since you last loaded the webpage. Please refresh the page."); 
     } else { 
      toastr.success("Vendor to location details saved"); 
      selectedLoc.vendortolocationid(result.VendorToLocationID); 
      self.updateVendorView(); // added 170307 1030 to get vendor contact details to update automatically 
      self.getActionLog(vendorid); 
      selectedLoc.needsave(false); 
     } 
     } 
    }); 

    }; 
} 

$(document).ready(function() { 

    var myViewModel = new VendorViewModel(); 
    ko.applyBindings(myViewModel); 
    myViewModel.updateVendorView(); 
    myViewModel.getLocationSubscription(curVendorID); 
} 

Das Ziel ist es, das Kontrollkästchen richtig zu funktionieren. Der Rest der Textbox-basierten Bindungen, die ich entfernt habe, um den Beitrag zu verdichten, funktioniert seit Jahren richtig. Ich bin jetzt ratlos, was ich falsch mache mit der Textbox.

+0

Ok, also habe ich, wenn ich „klicken: $ parent.selectedLocationSubscribed“ entfernen heraus das Symptom verschwindet aber, dass erkennbar ist, wie ich etwas isDirty Stil tat Verfolgen des Objekts, sodass ich weiß, ob das Panel/Objekt dem Benutzer erlauben muss, seine Änderungen zu speichern. Haben Sie Ideen, wie Sie die geprüfte Bindung an das Element erneut anwenden können? – Chris

Antwort

0

Lassen Sie mich erneut bestätigen, also versuchen Sie, die zugehörige Schaltfläche zu aktivieren, und aktivieren Sie das Kontrollkästchen, wenn ein Benutzer auf ein Element innerhalb <div class="well span3 ...>" klickt.

Ich habe alle Vorschläge direkt in den Code.

function VendorToLocation(vtl) { 
 
    var self = this; 
 
    self.vendortolocationid = ko.observable(vtl.vendortolocationid); 
 
    self.primarycontactname = ko.observable(vtl.primarycontactname); 
 
    self.vendorbringinggifts = ko.observable(vtl.vendorbringinggifts); 
 
    self.giftsarebeingbrought = ko.observable(vtl.giftsarebeingbrought); 
 
    self.needsave = ko.observable(vtl.needsave); 
 

 
    // I prefer to put all the logic in here instead of being embedded to the HTML 
 
    self.isCheckboxVisible = ko.pureComputed(function(){ 
 
    return self.vendorbringinggifts() === 0 || self.vendorbringinggifts() === self.vendortolocationid(); 
 
    }); 
 
} 
 

 
function VendorViewModel() { 
 
    var self = this; 
 
    self.locationssubscribed = ko.observableArray(
 
    [ 
 
     new VendorToLocation ({ 
 
     "vendortolocationid": 10, 
 
     "primarycontactname": "Fake Name1", 
 
     "vendorbringinggifts": 0, 
 
     "giftsarebeingbrought": false, 
 
     "needsave": false 
 
     }), 
 
     new VendorToLocation ({ 
 
     "vendortolocationid": 11, 
 
     "primarycontactname": "Fake Name2", 
 
     "vendorbringinggifts": 0, 
 
     "giftsarebeingbrought": false, 
 
     "needsave": false 
 
     }), 
 
     new VendorToLocation ({ 
 
     "vendortolocationid": 12, 
 
     "primarycontactname": "Fake Name3", 
 
     "vendorbringinggifts": 0, 
 
     "giftsarebeingbrought": false, 
 
     "needsave": false 
 
     }), 
 
     new VendorToLocation ({ 
 
     "vendortolocationid": 13, 
 
     "primarycontactname": "Fake Name4", 
 
     "vendorbringinggifts": 0, 
 
     "giftsarebeingbrought": false, 
 
     "needsave": false 
 
     }) 
 
    ] 
 
); 
 
    
 
    // To store the selected location 
 
    self.selectedLocationSubscribed = ko.observable(); 
 

 
    // To modify selected location, enable the button and modify the checkbox whenever user click on an element that uses this as its click event 
 
    self.selectLocationSubscribed = function(data, event) { 
 
    if(data !== null) { 
 
     self.selectedLocationSubscribed(data); 
 
    
 
     // If you want to change needsave of other properties to false (disable all other buttons) before that you can do it here 
 
     ko.utils.arrayForEach(self.locationssubscribed(), function(location) { 
 
     if(data.vendortolocationid() !== location.vendortolocationid()){ 
 
      location.needsave(false); 
 
      location.giftsarebeingbrought(false); 
 
     } 
 
     }); 
 
     // code ends here 
 
    
 
     // And then you modify the selected needsave the selected object to true to enable the button 
 
     data.needsave(true); 
 
     data.giftsarebeingbrought(true); 
 
    } 
 

 
    // To perform the default browser click action 
 
    return true; 
 
    } 
 
} 
 

 
$(document).ready(function() { 
 
    var myViewModel = new VendorViewModel(); 
 
    ko.applyBindings(myViewModel); 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> 
 

 
<div class="container span8" data-bind="foreach: locationssubscribed"> 
 
    <div class="well span3" data-bind="click: $parent.selectLocationSubscribed"> 
 
    <input type="text" class="span3" data-bind="value: primarycontactname" placeholder="Contact Name.." /> 
 
    <br />  
 
    <div class="checkbox" data-bind="visible: (vendorbringinggifts() === 0 || vendorbringinggifts() === vendorid())"> 
 
     <input id="chkGiftsAreBeingBrought" type="checkbox" data-bind="checked: giftsarebeingbrought" /> 
 
    </div> 
 
    <button data-bind="click: $root.saveVendorToLocation, enable: needsave, text: needsave() ? 'Save Location Changes' : 'No Changes to Save', css: { 'btn-primary': needsave }" class="btn">Save Location Changes</button> 
 
    </div> 
 
</div>

+0

Ich habe dies implementiert, aber das Problem bleibt, das Kontrollkästchen ändert sich nicht sichtbar, wenn Sie darauf klicken, aber das Debugging mit einem toJSON-Aufruf zeigt, dass sich die zugrunde liegenden Observablen mit dem ersten Klick ändern. Alle nachfolgenden Klicks ändern nichts. Es ist so, als ob das Kontrollkästchen seine 'angekreuzte' Datenbindung verliert, wenn 'selectedLocationSubscribed' geändert wird. Haben Sie noch weitere Ideen, um sicherzustellen, dass die Elemente ihre Checkbox-Funktionalität behalten? – Chris

+0

@Chris Ich habe die Antwort aktualisiert – muhihsan

+0

Vielen Dank für die Hilfe! Das funktioniert jetzt. Ich schätze wirklich die Zeit, die du damit verbracht hast. – Chris

0

Die click Bindung verhindert, dass die Standardaktion. So aktivieren Sie die Standardaktion: return true from the event handler. Dies bedeutet, dass Sie eine Observable nicht direkt an die click Bindung übergeben können.

click: $parent.handleClick 

JS:

self.handleClick = function (item) { 
    // do something with item 
    return true; // don't prevent default action 
} 
Verwandte Themen