This is my first time using knockout. Is this the correct way to structure the ViewModel? I'm reading/writing from a JSON file that's got a fair bit of nesting.
Creating the model to just write was easy. Getting it to also read the JSON required if/else statements in the mapping objects. Which I feel is not correct.
Any input would be greatly appreciated.
function Survey(name, panes, tester)
{
this.name = ko.observable(name);
this.panes = ko.observableArray([new Pane(panes)]);
this.tester = ko.observable(tester);
}
function Pane(panes)
{
//var panesCount = panes.length;
//console.log(panes[0].type);
if (panes) {
this.type = ko.observable(panes[0].type);
this.head = ko.observable(panes[0].head);
this.content = ko.observable(panes[0].content);
this.options = ko.observableArray([new PaneOptions(panes[0].options)]);
}
else {
this.type = ko.observable();
this.head = ko.observable();
this.content = ko.observable();
this.options = ko.observableArray([new PaneOptions()]);
}
}
function PaneOptions(options)
{
//console.log(options);
if (options) {
this.data = ko.observable(options[0].data);
this.target = ko.observable(options[0].target);
}
else {
this.data = ko.observable();
this.target = ko.observable();
}
}
function SurveyViewModel()
{
var self = this;
self.surveys = ko.observableArray([]);
$.getJSON("create/fetch", function(data) {
for (var i=0; i < data.surveys.length; i++) {
self.surveys.push(new Survey(data.surveys[i].name, data.surveys[i].panes, data.surveys[i].tester))
}
});
self.addSurvey = function ()
{
self.surveys.push(new Survey());
};
self.saveUserData = function()
{
var data_to_send = ko.toJSON(self);
$.post("create/save", data_to_send, function(data) {
console.log("Your data has been posted to the server!");
});
}
}
var vm = new SurveyViewModel();
ko.applyBindings(vm);
Here is the JSON representation:
{
"surveys": [
{
"name": "My First Survey1",
"panes": [
{
"type": "question1",
"head": "Heading Text1",
"content": "multichoice1",
"options": [
{
"data": "Time",
"target": 2
}
]
}
],
"tester": "default"
},
{
"name": "My Second Survey2",
"panes": [
{
"type": "response2",
"head": "Heading Text2",
"content": "multichoice2",
"options": [
{
"data": "Time",
"target": 2
}
]
}
],
"tester": "default2"
},
{
"name": "My Third Survey3",
"panes": [
{
"type": "thanks3",
"head": "Heading Text3",
"content": "multichoice3",
"options": [
{
"data": "Time",
"target": 2
}
]
}
],
"tester": "default3"
}
]
}
This is how I would do it.
JSFiddle Demo
var jsonData = {
"surveys": [{
"name": "My First Survey1",
"panes": [{
"type": "question1",
"head": "Heading Text1",
"content": "multichoice1",
"options": [{
"data": "Time",
"target": 2
}]
}],
"tester": "default"
}, {
"name": "My Second Survey2",
"panes": [{
"type": "response2",
"head": "Heading Text2",
"content": "multichoice2",
"options": [{
"data": "Time",
"target": 2
}]
}],
"tester": "default2"
}, {
"name": "My Third Survey3",
"panes": [{
"type": "thanks3",
"head": "Heading Text3",
"content": "multichoice3",
"options": [{
"data": "Time",
"target": 2
}]
}],
"tester": "default3"
}]
};
function Survey(name, panes, tester) {
var self = this;
self.name = ko.observable(name);
self.panes = ko.observableArray();
self.tester = ko.observable(tester);
var mappedPanes = $.map(panes, function (item, index) {
return new Pane(item);
});
self.panes(mappedPanes);
return self;
}
function Pane(pane) {
var self = this;
self.type = ko.observable(pane.type || '');
self.head = ko.observable(pane.head || '');
self.content = ko.observable(pane.content || '');
self.options = ko.observableArray();
var mappedOptions = $.map(pane.options, function (item, index) {
return new PaneOptions(item);
});
self.options(mappedOptions);
return self;
}
function PaneOptions(option) {
var self = this;
this.data = ko.observable(option.data || '');
this.target = ko.observable(option.target || '');
return self;
}
function SurveyViewModel() {
var self = this;
self.surveys = ko.observableArray([]);
/* Commented out as JSON data is included above
$.getJSON("create/fetch", function (data) {
$.each(jsonData.surveys, function (index, item) {
self.surveys.push(new Survey(item.name, item.panes, item.tester));
});
}
});
*/
$.each(jsonData.surveys, function (index, item) {
self.surveys.push(new Survey(item.name, item.panes, item.tester));
});
self.addSurvey = function () {
self.surveys.push(new Survey());
};
self.saveUserData = function () {
var data_to_send = ko.toJSON(self);
$.post("create/save", data_to_send, function (data) {
console.log("Your data has been posted to the server!");
});
};
}
var vm = new SurveyViewModel();
ko.applyBindings(vm);
Related
I need map this array to observable array.
actionsDataTime = {
"t16082209": [
{
"timeId": "16082209",
"id": 176,
"class_from": "09:00",
"class_to": "10:25",
"action": {
"name": "AQUA",
"color": "aqua",
"icon": ""
},
"trainer": {
"id": 348,
"name": "Art Edition"
},
"capacity": 11,
"capacity_left": 11,
"substitutes": 5,
"substitutes_left": 5,
"price": 1
}
],
"t16082308": [
{
"timeId": "16082308",
"id": 169,
"class_from": "08:00",
"class_to": "09:00",
"action": {
"name": "ZUMBA",
"color": "zumba",
"icon": ""
},
"trainer": {
"id": 210,
"name": "Adam Pt\u00e1\u010dek"
},
"capacity": 10,
"capacity_left": 10,
"substitutes": 5,
"substitutes_left": 5,
"price": 1
}
],
"t16082408": [
{
"timeId": "16082408",
"id": 173,
"class_from": "08:00",
"class_to": "09:05",
"action": {
"name": "KICK BOX",
"color": "box",
"icon": ""
},
"trainer": {
"id": 360,
"name": "Alexandra Galov\u00e1"
},
"capacity": 10,
"capacity_left": 10,
"substitutes": 5,
"substitutes_left": 5,
"price": 2
},
{
"timeId": "16082408",
"id": 175,
"class_from": "08:00",
"class_to": "09:05",
"action": {
"name": "KICK BOX",
"color": "box",
"icon": ""
},
"trainer": {
"id": 360,
"name": "Alexandra Galov\u00e1"
},
"capacity": 10,
"capacity_left": 10,
"substitutes": 5,
"substitutes_left": 5,
"price": 2
}
]
}
Section "t16082308" is some timestamp that I need in app so it is dynamic. Number of actions in array can be changed be too.
I am able to map this by mapping module this way
ko.mapping.fromJS(actionsDataTime, self.actionsData);
but when i need to reload it from server like this
self.reloadActions = function() {
$.ajax({
type: 'GET',
url: {link reloadActions! },
dataType: "json",
success: function(data) {
ko.mapping.fromJS(data, {}, self.actionsData);
}
})
};
and is there a new timestamp section or soma new action - nothing changes in frontend and it looks that not all things are mapped as observables. When I only change some value like "capacity" it works fine.
How can I map it better (all to observables) so I can see change when actions is added or deleted?
This is how I would do it:
var actionObj = function (data) {
this.name = ko.observable();
this.color = ko.observable();
this.icon = ko.observable();
this.update(data);
}
ko.utils.extend(actionObj.prototype, {
update: function (data) {
this.name = ko.observable(data.name || '');
this.color = ko.observable(data.color || '');
this.icon = ko.observable(data.icon || '');
}
});
self.Action = function (data) {
return new actionObj(data);
}
var trainerObj = function (data) {
this.id = ko.observable();
this.name = ko.observable();
this.update(data);
}
ko.utils.extend(trainerObj.prototype, {
update: function (data) {
this.id = ko.observable(data.id || '');
this.name = ko.observable(data.name || '');
}
});
self.Trainer = function (data) {
return new trainerObj(data);
}
var actionsDataTimeObj = function (data) {
this.timeId = ko.observable();
this.id = ko.observable();
this.class_from = ko.observable();
this.class_to = ko.observable();
this.action = ko.observableArray();
this.trainer = ko.observableArray();
this.capacity = ko.observable();
this.capacity_left = ko.observable();
this.substitutes = ko.observable();
this.substitutes_left = ko.observable();
this.price = ko.observable();
this.update(data);
}
ko.utils.extend(actionsDataTimeObj.prototype, {
update: function (data) {
this.timeId = ko.observable(data.timeId || '');
this.id = ko.observable();
this.class_from = ko.observable();
this.class_to = ko.observable();
var _action = $.map(data.action, function (item) {
return new self.Action(item);
});
this.action(_action);
var _trainer = $.map(data.trainer, function (item) {
return new self.Trainer(item);
});
this.trainer(_trainer);
this.capacity = ko.observable();
this.capacity_left = ko.observable();
this.substitutes = ko.observable();
this.substitutes_left = ko.observable();
this.price = ko.observable();
}
});
self.ActionsDataTime = function (data) {
return new actionsDataTimeObj(data);
}
Basically you have to declare your "action" and "trainer" as ObservableArrays and then map the data to them in the update function of the ActionsDataTime object. Then everything will be observables.
Oh, then:
self.actionsData = ko.observableArray();
var _actiondatatimes = $.map(data, function (item) {
return new self.ActionDataTime(item);
});
self.actionsData(_actiondatatimes);
how can i solve this error "Cannot read property 'length' of undefined at checkWithSeletedModel".
when i add object directly in controller its working but when data coming from api i am getting error
TypeError: Cannot read property 'length' of undefined
at checkWithSeletedModel (newbooking.html:404)
at new MyCtrlFun (newbooking.html:391)
at invoke (angular-1.0.1.js:2795)
at Object.instantiate (angular-1.0.1.js:2805)
at angular-1.0.1.js:4620
at angular-1.0.1.js:4201
at forEach (angular-1.0.1.js:117)
at nodeLinkFn (angular-1.0.1.js:4186)
at compositeLinkFn (angular-1.0.1.js:3838)
at compositeLinkFn (angular-1.0.1.js:3841)
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
myApp.controller("MyCtrl", MyCtrlFun);
MyCtrlFun.$inject = ['$scope', '$filter', '$timeout','$http'];
function MyCtrlFun($scope, $filter, $timeout,$http) {
//****** Selected List****
$scope.selectedlist = ["Lumia 735 TS", "Lumia 510"];
$scope.checkbox_model = [];
$scope.checkbox_list = [];
$scope.submitModel = [];
var submodel = [];
var models = {};
var brandname = {};
$scope.finalOutput = {
city:null,
Storename : null,
Offerid : null,
Offer_price : null,
Total_price : null,
Sub_Total_price : null,
Categories : []
}
$scope.finalOutput_withNullFilter = {};
$scope.checkItems = function(){
$scope.checkbox_list = [];
$scope.selectedlist = new Array();
for(var item in $scope.checkbox_model){
if($scope.checkbox_model[item].isChecked)
{
$scope.selectedlist.push($scope.checkbox_model[item].name);
$scope.checkbox_list.push($scope.checkbox_model[item]);
}
}
$scope.checkbox_list.push({offer_id : $scope.selected_offer_id});
//alert(Storename)
/*var m = priceChangeToOffer($scope.selected_offer_id);
if(!isNaN(m)){
$scope.total_price =$scope.total_price-parseInt(m);
}*/
$scope.checkbox_list.push({sub_total : $scope.sub_total});
checkWithSeletedModel();
$scope.finalOutput.city=$scope.phones[0].city;
$scope.finalOutput_withNullFilter = $scope.finalOutput;
if($scope.finalOutput.Storename==null)
{
$scope.finalOutput.Storename = $scope.phones[0].Storename;
}
if($scope.finalOutput.Offerid==null)
{
delete $scope.finalOutput.Offerid;
}
if($scope.finalOutput.Offer_price==null)
{
delete $scope.finalOutput.Offer_price;
}
alert(JSON.stringify($scope.finalOutput));
//****** redefine finalOutput after Submit data to server
$scope.finalOutput = {
city:null,
Storename : null,
Offerid : null,
Offer_price : null,
Total_price : null,
Sub_Total_price : null,
Categories : []
}
}
$scope.selectedbrand = 'Nokia';
$scope.submodel ='Lumia';
$http.get('http://19.168.1.4/shop1/').success(function(data, status, response)
{
//$scope.phones = data
//console.log($scope.phones);
//console i am getting object .here i have added what i have got in console
$scope.phones = [{
"_id": {
"$oid": "56a9c44f40d0275643cfc04e"
},
"default": [],
"Categories": [
{
"models": [
{
"submodel": [
{
"price": "Not available",
"name": "Lumia 735 TS"
},
{
"price": "8100",
"name": "Lumia 510"
},
{
"price": "9900",
"name": "Lumia 830"
}
],
"name": "Lumia"
},
{
"submodel": [
{
"price": "10000",
"name": "Asha 230"
},
{
"price": "11999",
"name": "Asha Asn01"
}
],
"name": "Asha"
}
],
"brandname": "Nokia",
"id": "986745"
},
{
"models": [
{
"submodel": [
{
"price": "5000",
"name": "Trend 840"
},
{
"price": "6999",
"name": "A5"
}
],
"name": "Galaxy"
},
{
"submodel": [
{
"price": "12000",
"name": "Asha 230"
}
],
"name": "Asha"
}
],
"brandname": "Samsung",
"id": "144745"
}
],
"Storename": "Zig Zag Mobiles",
"Shopid":"asdef1234",
"city":"bengaluru",
"__v": 0
}
]
});
//----------------------------Our Shop Offers----------------------------------------
$http.get('http://19.168.1.4/offers/').success(function(data, status, response)
{
//$scope.offers =data;
//console.log($scope.offers);
//console i am getting object .here i have added what i have got in console
$scope.offers = [
{
id: "as23456",
"Storename": "Zig Zag Mobiles",
"Shopid":"asdef1234",
"Offer_message":"1000rs off",
"Categories": [
{
"models": [
{
"submodel": [
{
"price": "1000",
"name": "Lumia 735 TS"
}
],
"name": "Lumia"
}
],
"brandname": "Nokia",
"id": "986745"
}
],
},{
id: "de34575",
"Storename": "Zig Zag Mobiles",
"Shopid":"asdef1234",
"Offer_message":"500rs off",
"Categories": [
{
"models": [
{
"submodel": [
{
"price": "500",
"name": "Lumia 830"
}
],
"name": "Lumia"
}
],
"brandname": "Nokia",
"id": "345645"
}
],
},
{
id: "ert25675",
"Storename": "Zig Zag Mobiles",
"Shopid":"asdef1234",
"Offer_message":"100 Flat",
"Categories": [
{
"models": [
{
"submodel": [
{
"price": "100",
"name": "Asha 230"
}
],
"name": "Asha"
}
],
"brandname": "Samsung",
"id": "345645"
}
],
}
]
});
$scope.offerSelectedList = [];
$scope.total_price = 0, $scope.sub_total=0;
$scope.changeItemStateFun = function(checkbox_value){
if(checkbox_value.isChecked){
if(!isNaN(checkbox_value.price)){
$scope.total_price =$scope.total_price+parseInt(checkbox_value.price);
}
var checked_offer = getOffer([checkbox_value]);
if(checked_offer!=false){
$scope.offerSelectedList.push(checked_offer);
//alert(checked_offer.Categories[0].models[0].submodel[0].name);
}
}else{
if(!isNaN(checkbox_value.price)){
$scope.total_price = $scope.total_price-parseInt(checkbox_value.price);
}
var checked_offer = getOffer([checkbox_value]);
if(checked_offer!=false){
var tempOfferList = [];
for(var i in $scope.offerSelectedList){
if($scope.offerSelectedList[i].id!=checked_offer.id){
tempOfferList.push($scope.offerSelectedList[i]);
}
}
$scope.offerSelectedList = tempOfferList;
}
}
$scope.sub_total = $scope.total_price;
$scope.finalOutput.Total_price = $scope.total_price;
$scope.finalOutput.Sub_Total_price = $scope.sub_total;
}
$scope.selected_offer_id = null;
$scope.submit_offer = {};
$scope.offerSeleted = function(offer){
$scope.selected_offer_id = offer;
var m = priceChangeToOffer($scope.selected_offer_id);
if(!isNaN(m.Offer_price)){
$scope.sub_total =$scope.total_price-parseInt(m.Offer_price);
}
$scope.finalOutput.Storename = m.Storename;
$scope.finalOutput.Offerid = m.Offerid;
$scope.finalOutput.Offer_price = m.Offer_price;
$scope.finalOutput.Total_price = $scope.total_price;
$scope.finalOutput.Sub_Total_price = $scope.sub_total;
}
function getOffer(checkedItem){
for(var i=0; i<checkedItem.length; i++){
for(var j=0; j<$scope.offers.length; j++){
for(var k=0;k<$scope.offers[j].Categories.length; k++){
for(var m=0; m<$scope.offers[j].Categories[k].models.length; m++){
for(var n=0; n<$scope.offers[j].Categories[k].models[m].submodel.length; n++){
if($scope.offers[j].Categories[k].models[m].submodel[n].name==checkedItem[i].name){
return $scope.offers[j];
}
}
}
}
}
}
return false;
}
//-----------------------------------------------------------------------------------
checkWithSeletedModel();
function checkWithSeletedModel(){
$scope.finalOutput.Categories = [];
$scope.submitModel = [];
submodel = [];
models = {};
brandname = {};
$scope.offerSelectedList = [];
$scope.total_price = 0;
$scope.checkbox_model = [];
for(var i=0; i<$scope.phones.length; i++){
for(var j=0; j<$scope.phones[i].Categories.length; j++){
if($scope.phones[i].Categories[j].brandname==$scope.selectedbrand){
brandname = {
id : $scope.phones[i].Categories[j].id,
brandname : $scope.phones[i].Categories[j].brandname,
models : []
};
models = {};
for(var k=0; k<$scope.phones[i].Categories[j].models.length; k++){
if($scope.phones[i].Categories[j].models[k].name==$scope.submodel){
models = {
name : $scope.phones[i].Categories[j].models[k].name,
submodel : []
}
for(var m=0; m<$scope.phones[i].Categories[j].models[k].submodel.length; m++){
var verifyIsCheck = false;
if($scope.selectedlist.length>0){
verifyIsCheck=verifyIsChecked($scope.phones[i].Categories[j].models[k].submodel[m].name);
}
if(verifyIsCheck==true){
models.submodel.push({name : $scope.phones[i].Categories[j].models[k].submodel[m].name, price:($scope.phones[i].Categories[j].models[k].submodel[m].price=='Not available'?null:$scope.phones[i].Categories[j].models[k].submodel[m].price)});
//models.submodel
}
var obj1 = {isChecked :verifyIsCheck, name : $scope.phones[i].Categories[j].models[k].submodel[m].name, price:$scope.phones[i].Categories[j].models[k].submodel[m].price};
//$scope.changeItemStateFun(obj1);
var checkedOffer = getOffer([obj1]);
if(checkedOffer!=false && verifyIsCheck==true){
$scope.offerSelectedList.push(checkedOffer);
}
if(verifyIsCheck==true && !isNaN(obj1.price)){
$scope.total_price = $scope.total_price+parseInt(obj1.price);
}
$scope.checkbox_model.push(obj1);
}
}
}
brandname.models.push(models);
$scope.submitModel.push(brandname);
}
}
}
$scope.finalOutput.Categories.push($scope.submitModel);
}
function verifyIsChecked(submodel_name){
for(var i=0; i<$scope.selectedlist.length; i++){
if($scope.selectedlist[i]==submodel_name){
return true;
}
}
return false;
}
//********** For total sum checked model and change according to offer
function priceChangeToOffer(offer_id){
for(var j=0; j<$scope.offers.length; j++){
if(offer_id!=$scope.offers[j].id)
continue;
for(var k=0;k<$scope.offers[j].Categories.length; k++){
for(var m=0; m<$scope.offers[j].Categories[k].models.length; m++){
for(var n=0; n<$scope.offers[j].Categories[k].models[m].submodel.length; n++){
var offer_obj = {
Storename : $scope.offers[j].Storename,
Offerid : $scope.offers[j].id,
Offer_price : $scope.offers[j].Categories[k].models[m].submodel[0].price
};
return offer_obj;
}
}
}
}
}
$scope.sub_total = $scope.total_price;
$scope.finalOutput.Total_price = $scope.total_price;
$scope.finalOutput.Sub_Total_price = $scope.sub_total;
}
myApp.filter("removespace", function(){
return function(input){
return input.replace(/[^A-Z0-9]+/ig, "_")
}
});
//]]>
//]]>
//]]>
<script type="text/javascript" src="http://code.angularjs.org/angular-1.0.1.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="item" ng-repeat="item in phones">
<div ng-repeat="cat in item.Categories" ng-show="cat.brandname==selectedbrand">
<h2><b>{{ cat.brandname }}</b></h2>
<div ng-repeat="models in cat.models" ng-show="models.name==submodel">
<h3>
<b>{{models.name}}</b>
</h3>
<div ng-repeat="submodels in models.submodel">
<input type="checkbox" ng-model="checkbox_model[$index].isChecked" ng-change="changeItemStateFun(checkbox_model[$index])"/>{{ submodels.name }}
</div><br/><br/>
<b>Sub Total = {{sub_total}}</b><br/>
<select ng-show="offerSelectedList.length>0" ng-model="selected_item" ng-options="offer.id as offer.Offer_message for offer in offerSelectedList" ng-change="offerSeleted(selected_item)">
<option>select offer</option>
</select>
</div>
</div>
<button ng-click="checkItems()">Do</button>
</div>
</div>
how can i solve this pls some one help me out to move forward i have added my code below .
demo
You have kept a for loop like this:
for(var i=0; i<$scope.phones.length; i++)
here you are trying to access the length of $scope.phones variable. But you have defined $scope.phones inside the success callback of your api call. But your api calls are all failing. therefore success callback are never getting called and therefore $scope.phones is always undefined. Thus you are getting error that `cannot read length of undefined'.
Is there is a way to transform this JSON Object using Angular? I need to transform the JSON object from this format:
$scope.TestJson = {
"filters": [
{
"dataPropertyID": "VoidType",
"label": "Homeless"
},
{
"dataPropertyID": "VoidType",
"label": "Mainstream"
},
{
"dataPropertyID": "PropertyType",
"label": "Flat"
},
{
"dataPropertyID": "PropertyType",
"label": "Cottage"
}
]
}
To this format:
$scope.NewTestJson = {
"filters": [
{
"dataPropertyID": "VoidType",
"label":[ "Homeless","Mainstream"]
},
{
"dataPropertyID": "PropertyType",
"label":[ "Flat", "Cottage"]
}
]
}
I think this is more a JavaScript question than anything else. Nonetheless:
$scope.NewTestJson = {
filters: [];
};
// Do something for all (old) filter items
$scope.TestJson.filters.forEach(function(filter) {
// Try to get the existing (new) filter
var newFilter = $scope.NewTestJson.filters.filter(function(newFilter) {
return newFilter.dataPropertyID === filter.dataPropertyID;
}).shift();
// If the new filter does not exist, create it
if (!newFilter) {
newFilter = {
dataPropertyID: filter.dataPropertyID,
label: []
};
$scope.NewTestJson.filters.push(newFilter);
}
// Finally, add the old filter label to the new filter
newFilter.label.push(filter.label);
});
json = {
"filters": [
{
"dataPropertyID": "VoidType",
"label": "Homeless"
},
{
"dataPropertyID": "VoidType",
"label": "Mainstream"
},
{
"dataPropertyID": "PropertyType",
"label": "Flat"
},
{
"dataPropertyID": "PropertyType",
"label": "Cottage"
}
]
};
newJson = new Object();
newJson.filters = new Array();
for (var element in json.filters) {
var check = 0;
for (var element2 in newJson.filters) {
if (json.filters[element].dataPropertyID === newJson.filters[element2].dataPropertyID) {
newJson.filters[element2].label.push(json.filters[element].label);
check = 1;
}
}
if (check == 0) {
var Obj = new Object();
Obj.dataPropertyID = json.filters[element].dataPropertyID;
Obj.label = new Array();
Obj.label.push(json.filters[element].label);
newJson.filters.push(Obj);
}
}
I have an issue about checking for an existing product in knockoutjs.
The problem is: if the product exists in Cart Line, the product quantity will increase, if not, it will be added to Cart
This is code:
var CartLine = function (productid,productName, price, quantity) {
var self = this;
self.resultId = ko.observable(productid);
self.resultProduct = ko.observable(productName);
self.resultPrice = ko.observable(price);
self.resultQuantity = ko.observable(quantity || 1);
self.subtotal = ko.computed(function () {
return self.resultPrice() * self.resultQuantity();
});
};
$('#addProduct').click(function (line) {
var context = ko.contextFor(this);
var existing = self.find(line.resultId);
var lines = self.lines();
if (existing) {
existing.resultQuantity = existing.resultQuantity() + context.$data.Quantity();
}else{
existing = new CartLine(self.product().productid, self.product().name, self.product().price, context.$data.Quantity());
self.lines.push(existing);
}
return existing;
});
self.find = function (productid) {
return ko.utils.arrayFirst(self.lines(), function (line) {
return line.resultId === productid;
});
};
This is the full code: http://jsfiddle.net/pf9hd3Lg/2/
There are a number of errors with the code you have listed above. The below should work for the scenario you described. I have tried to comment my changes in the code below.
var CartLine = function (productid,productName, price, quantity) {
var self = this;
self.resultId = ko.observable(productid);
self.resultProduct = ko.observable(productName);
self.resultPrice = ko.observable(price);
self.resultQuantity = ko.observable(quantity || 1);
self.subtotal = ko.computed(function () {
return self.resultPrice() * self.resultQuantity();
});
};
var Cart = function() {
var self = this;
self.products = ko.observableArray([{
"productid": "1",
"name": "CAPUCINO ",
"price": 170
},
{
"productid": "2",
"name": "Sữa bò tươi",
"price": 140
}
,
{
"productid": "3",
"name": "Phô mai mặn",
"price": 170
}, {
"productid": "4",
"name": "Bơ đậu phộng ",
"price": 150
},
{
"productid": "5",
"name": "Bạc Hà",
"price": 160
},
{
"productid": "6",
"name": "Dâu Tây",
"price": 160
}
]);
self.product = ko.observable("");
self.Quantity = ko.observable(1).extend({ numeric: 0 });
self.price = ko.observable();
self.productid = ko.observable("");
self.lines = ko.observableArray();
self.grandTotal = ko.pureComputed(function () {
var total = 0;
$(self.lines()).each(function (index, line) { total += line.subtotal() })
return total;
});
$('#addProduct').click(function (line) {
var context = ko.contextFor(this);
var existing = self.find();
var lines = self.lines();
if (existing) {
//existing.resultQuantity is also an observable and should be set this way and not with the = operator
existing.resultQuantity(existing.resultQuantity() + context.$data.Quantity());
}else{
existing = new CartLine(self.product().productid, self.product().name, self.product().price, context.$data.Quantity());
self.lines.push(existing);
}
return existing;
});
self.removeProduct = function (line,event) {
self.lines.remove(line);
};
self.find = function () {
return ko.utils.arrayFirst(self.lines(), function (line) {
//resultId is an observable
//self.product().productid is what you are interested in, no need to pass it into the function
return line.resultId() === self.product().productid;
});
};
}
ko.applyBindings(new Cart());
I'm trying to remove obects from an object if they appear in other objects. Really hard to exaplin! Here's an example. I have 2 Objects containing DOM image objects and I would like the DOM image objects removed from the first object if they appear in the second object.
First Object
{
"241": [{
"img": image_object_1
},
{
"img": image_object_2
},
{
"img": image_object_3
},
{
"img": image_object_4
}]
}
Second Object
{
"241": [{
"img": image_object_1
},
{
"img": image_object_3
},
{
"img": image_object_4
}]
}
Expected result of object 1
{
"241": [{
"img": image_object_2
}]
}
I have everything in a single object like so but I'm happy to change the format if needs be
{
"0": {
},
"1": {
"241.14999389648438": [{
"img": {
image_object_1
},
},
{
"img": {
image_object_2
},
},
{
"img": {
image_object_3
},
},
{
"img": {
image_object_4
},
}]
},
"2": {
"241.14999389648438": [{
"img": {
image_object_2
},
},
{
"img": {
image_object_3
},
},
{
"img": {
image_object_4
},
}]
}
}
My working code is here
jQuery.fn.reverse = [].reverse;
function same_height(){
var imob = {};
var groups = [];
var heights = [];
var tp = 0;
var img = false;
$("#ez-container .row").each(function(gi){
imob = {};
groups[gi] = {};
heights[gi] = {};
tp = 0;
img = false;
$(this).find(".ez-image img").each(function(){
img = $(this);
tp = img.offset().top;
imob = {
"img":img,
"padding":img.outerHeight(true) - (parseInt(img.css('borderBottomWidth'))+parseInt(img.css('borderTopWidth'))) - img.innerHeight()
};
if(typeof(groups[gi][tp])=="undefined"){
groups[gi][tp] = [];
heights[gi][tp] = [];
}
groups[gi][tp].push(imob);
heights[gi][tp].push(img.height());
});
});
heights.reverse();
var max_group_height = 0;
$.each(groups.reverse(),function(gix,grp){
$.each(grp,function(t,im){
if(im.length>1){
$.each(im,function(i,v){
max_group_height = Math.max.apply(Math, heights[gix][t]);
if(typeof(v.img.attr("data-fixed"))=="undefined"){
v.img.css({"height":max_group_height+(v.padding)+"px"}).attr("data-height",0).attr("data-width",0).attr("data-fixed",1);
}
});
}
});
});
do_swap_images();
}
if you checking dom image node, you need isSameNode functions. I am not sure about your requirements, hope below code will helps
//suppose a, b are your objects
var key = 241
var diff = a[key].filter( function( v ){
var firstImgNode = v.img;
return !b[key].some( function( v ){
return v.img.isSameNode( firstImgNode );
});
});
or if you checking other data type, then simply do v.img == firstImgNode