Knockout JS changing my viewmodel creation to use mapping pulgin - javascript

I am relatively new to Knockout.js and have a question regarding the creating of the view model.
What I am currently doing is:
viewModel = {
Menu: ko.observableArray(ko.utils.parseJson(data)),
editMenu: function (menu) {
ko.applyBindings(menu, document.getElementById("MenuCategories"));
$("#MenuCategories").bPopup();
}
There is more than one function, but trying to keep it short.
What I want to do is use the mapping plugin because my json data that I am using contains arrays of objects with each object containing an array and each object in that array also contains an array. What the JSON looks like:
[
{
"Id": 1,
"Name": "Test 5",
"Description": "Testing menu",
"BeveragesMenu": false,
"Active": true,
"Categories": [
{
"Id": 1,
"Name": "Test 1",
"Active": true,
"MenuItems": [
{
"Id": 1,
"Name": "Food",
"Description": "2 Eggs and Bread",
"Price": 50,
"DateBased": false,
"PriceOnRequest": false,
"DateFrom": null,
"DateTo": null,
"Active": true
}
]
},
{
"Id": 2,
"Name": "Test 2",
"Active": true,
"MenuItems": [
]
},
{
"Id": 1004,
"Name": "test",
"Active": true,
"MenuItems": [
]
},
{
"Id": 1005,
"Name": "Test 4",
"Active": true,
"MenuItems": [
]
}
]
},
{
"Id": 92,
"Name": "Test 4",
"Description": "",
"BeveragesMenu": false,
"Active": false,
"Categories": [
{
"Id": 1006,
"Name": "Test 1",
"Active": true,
"MenuItems": [
{
"Name": "Test",
"Description": "",
"Price": "",
"DateBased": false,
"PriceOnRequest": false
}
]
}
]
},
{
"Id": 93,
"Name": "Test 6",
"Description": "",
"BeveragesMenu": false,
"Active": false,
"Categories": [
]
},
{
"Id": 94,
"Name": "Test 9",
"Description": "",
"BeveragesMenu": false,
"Active": false,
"Categories": [
]
},
{
"Id": 95,
"Name": "Test 20]",
"Description": "",
"BeveragesMenu": false,
"Active": false,
"Categories": [
{
"Id": 4,
"Name": "Test 6666",
"Active": true,
"MenuItems": [
]
}
]
},
{
"Id": 96,
"Name": "Test 444",
"Description": "",
"BeveragesMenu": false,
"Active": false,
"Categories": [
{
"Id": 3,
"Name": "Test 555",
"Active": true,
"MenuItems": [
]
},
{
"Id": 5,
"Name": "Test 6666",
"Active": true,
"MenuItems": [
]
},
{
"Id": 1003,
"Name": "test 777",
"Active": true,
"MenuItems": [
]
}
]
}
]
Sorry for the long JSON code paste.
So now I am running into problems when updating certain parts of the objects within arrays withing objects etc.
So I taught that the mapping plugin might solve my problem as it creates all arrays as observable and I am assuming that is my problem.
So I tried:
viewModel = {
Menu: ko.mapping.fromJSON(ko.utils.parseJson(data)),
//Menu: ko.observableArray(ko.utils.parseJson(data)),
editMenu: function (menu) {
ko.applyBindings(menu, document.getElementById("MenuCategories"));
$("#MenuCategories").bPopup();
},
But then none of my binding are working and I can't seem to find the cause, any advice or tips on this matter would be appreciated.
Here is a Fiddle of all the things I have tried. http://jsfiddle.net/armandvdwalt/pjJc2/3/
Thanks

Try this fiddle, I switched the order of the resources. You were referencing the mapping plugin before knockout which was generating a script error about not recognizing "ko." Also, you don't need to use ko.utils.parseJson when using fromJSON, as fromJSON expects JSON as an argument.

Related

How to filter or delete parent node and make child node as parent node

I have a tree json, please check it below.
I want to delete parent node and make child node as parent node?
Or if I can is there any way to filter nodes from tree please look into below original json tree and expected json tree.
Original JSON IS
[
{
"Id": "224146",
"Text": "Node One",
"Depth": 0,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
]
},
{
"Id": "224135",
"Text": "Node two",
"Depth": 0,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
{
"Id": "224136",
"Text": "Client Summary",
"Depth": 1,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
{
"Id": "224137",
"Text": "Manager 1",
"Depth": 2,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
]
}
]
}
]
},
{
"Id": "224147",
"Text": "Node three",
"Depth": 0,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
]
}
]
Expected Value That I want IS.
Here I have remove Client Summary parent and make Manage 1 as parent.
[
{
"Id": "224146",
"Text": "Node one",
"Depth": 0,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
]
},
{
"Id": "224135",
"Text": "Node two",
"Depth": 0,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
{
"Id": "224137",
"Text": "Manager 1",
"Depth": 2,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
]
}
]
},
{
"Id": "224147",
"Text": "Node three",
"Depth": 0,
"IsSelected": false,
"IsExpanded": false,
"Nodes": [
]
}
]
I want this solution dynamically because this is a sample json that i have posted here thanks in advance.
Thanks
Kushal shah
You'll have to recursively traverse the whole hierarchy, and when you have a matching item, remove it from the array it is in, and insert at that position all the children items.
Here is a function that will perform such a node removal based on a given id.
function remove(arr, delId) {
const target = arr.findIndex(({Id}) => Id == delId);
if (target >= 0) {
arr.splice(target, 1, ...arr[target].Nodes);
} else {
arr.forEach(({Nodes}) => remove(Nodes, delId));
}
}
// demo
const data = [{"Id": "224146","Text": "Node One","Depth": 0,"IsSelected": false,"IsExpanded": false,"Nodes": []},{"Id": "224135","Text": "Node two","Depth": 0,"IsSelected": false,"IsExpanded": false,"Nodes": [{"Id": "224136","Text": "Client Summary","Depth": 1,"IsSelected": false,"IsExpanded": false,"Nodes": [{"Id": "224137","Text": "Manager 1","Depth": 2,"IsSelected": false,"IsExpanded": false,"Nodes": []}]}]},{"Id": "224147","Text": "Node three","Depth": 0,"IsSelected": false,"IsExpanded": false,"Nodes": []}];
remove(data, "224136");
console.log(data);

Related content from JSON & API

i have a json returned from an api that shows latest discussions from a forum..
the url that display the json output is like:
https://example.com/api/discussions?isApproved=true&exists=true&sort=-lastPostedAt
and this is the json output:
"links": {
"first": "http://localhost/flarum/public/api/discussions?isApproved=true\u0026exists=true\u0026sort=-lastPostedAt",
"next": "http://localhost/flarum/public/api/discussions?isApproved=true\u0026exists=true\u0026sort=-lastPostedAt\u0026page%5Boffset%5D=20"
},
"data": [
{
"type": "discussions",
"id": "46",
"attributes": {
"title": "footer",
"slug": "46-footer",
"commentCount": 1,
"participantCount": 1,
"createdAt": "2021-09-20T07:14:18+00:00",
"lastPostedAt": "2021-09-20T07:14:18+00:00",
"lastPostNumber": 1,
"canReply": true,
"canRename": true,
"canDelete": true,
"canHide": true,
"lastReadAt": "2021-09-20T07:14:20+00:00",
"lastReadPostNumber": 1,
"isApproved": true,
"canTag": true,
"subscription": null,
"isLocked": false,
"canLock": true
},
"relationships": { "user": { "data": { "type": "users", "id": "1" } }, "lastPostedUser": { "data": { "type": "users", "id": "1" } }, "tags": { "data": [{ "type": "tags", "id": "2" }] } }
},
{
"type": "discussions",
"id": "45",
"attributes": {
"title": "fhgfhfg",
"slug": "45-fhgfhfg",
"commentCount": 2,
"participantCount": 1,
"createdAt": "2021-09-19T16:07:37+00:00",
"lastPostedAt": "2021-09-19T23:04:00+00:00",
"lastPostNumber": 2,
"canReply": true,
"canRename": true,
"canDelete": true,
"canHide": true,
"lastReadAt": "2021-09-19T23:04:02+00:00",
"lastReadPostNumber": 2,
"isApproved": true,
"canTag": true,
"subscription": null,
"isLocked": false,
"canLock": true
},
"relationships": { "user": { "data": { "type": "users", "id": "1" } }, "lastPostedUser": { "data": { "type": "users", "id": "1" } }, "tags": { "data": [{ "type": "tags", "id": "2" }] } }
},
{
"type": "discussions",
"id": "39",
"attributes": {
"title": "Discussion",
"slug": "39-discussion",
"commentCount": 21,
"participantCount": 1,
"createdAt": "2021-05-22T11:06:43+00:00",
"lastPostedAt": "2021-09-04T12:49:32+00:00",
"lastPostNumber": 28,
"canReply": true,
"canRename": true,
"canDelete": true,
"canHide": true,
"lastReadAt": "2021-09-04T12:49:34+00:00",
"lastReadPostNumber": 28,
"isApproved": true,
"canTag": true,
"subscription": null,
"isLocked": false,
"canLock": true
},
"relationships": { "user": { "data": { "type": "users", "id": "1" } }, "lastPostedUser": { "data": { "type": "users", "id": "1" } }, "tags": { "data": [{ "type": "tags", "id": "1" }] } }
}
what i want to do is to have something like "related content" based on a discussion title. For example if i have this title "lets talk about cars", the json must shows all the discussions related to this title.
is this possible?
You can take the data from json and just filter the content inside
const filteredResults = yourJsonResponse.data.filter(item => item.attributes.title === 'lets talk about cars')
This won't be a good idea. as you're getting paginated list with limit(like per page 20/30). if you're using js you can use js filter for getting related content. But as i said. that filer will be done based on your current page data, not all data. it's better to use another api end for related content from large data..

how to map an array in an object map to another array

i have an object
{
"parent_entity_id": 394,
"display_name": "Test POI",
"event_code_prefix": "TEST",
"address": null,
"logo_url": "https://storage.png",
"is_active": true,
"identifier": [
{
"model_id": 10,
"entity_id": 575,
"is_active": true,
"valid_value": [
{
"type": "MACID",
"value": "AC:23:3F:23:8D:A1"
}
],
"display_name": "Test BLE Beacon 1",
"is_mandatory": true,
"entity_type_key": "BTBACID"
},
{
"model_id": null,
"entity_id": 576,
"is_active": true,
"valid_value": [
{
"type": "GEOFENCE_CIRCLE",
"value": {
"latitude": 24.155678,
"longitude": 54.425175,
"radius_in_meters": 500
}
}
],
"display_name": "Test tower gate 1",
"is_mandatory": true,
"entity_type_key": "GIS"
}
]
}
I need to map the array valid values from the object to another array with condition.
if Ble the map to valid_value_BLE array and if GIS to valid_values_GIS
try this
arr1=Obj.identifier.map(z => {
if(z.entity_type_key=='GIS'){z['valid_value_GIS']=z.valid_value;
}else{z['valid_value_BLE']=z.valid_value;}
delete z.valid_value; return z;
});
https://codepen.io/vkv88/pen/LYVZdwz?editors=0010

How to return a childobject from json with lodash?

Suppose I have the following json file and I would like to return the 'existing.primaryBundle.products' array preferrably with lodash:
{
"existing": {
"hasPlatinum": false,
"primaryBundle": {
"id": "2008",
"name": "TV - Entertainment, Sport",
"products": [
{
"name": "Entertainment",
"id": "100",
"price": 2600,
"gifted": false
},
{
"name": "Sport",
"id": "107",
"price": 2500,
"gifted": false,
"swappableProducts": [
{
"name": "Movies",
"id": "105",
"price": 2000,
"gifted": false
}
]
}
]
},
"extrasBundle": {
"id": "131",
"name": "Optional Extras - MUTV (Sports), LFCTV (Sports), Chelsea TV (Sports)",
"products": [
{
"name": "MUTV (Sports)",
"id": "665",
"price": 0,
"gifted": false
},
{
"name": "LFCTV (Sports)",
"id": "666",
"price": 0,
"gifted": false
},
{
"name": "Chelsea TV (Sports)",
"id": "667",
"price": 0,
"gifted": false
}
]
}
}
}
I have tried lodash and use this statement:
list2 = _.pick(existing,'primaryBundle.products')
But this returns an error and not the wanted result. How can I select this products array?
you could use _.get(nameOfObject, 'existing.primaryBundle.products') of course you would need to name your object like I've done below with sampleObject;
check out the lodash docs too
const sampleObject = {
"existing": {
"hasPlatinum": false,
"primaryBundle": {
"id": "2008",
"name": "TV - Entertainment, Sport",
"products": [{
"name": "Entertainment",
"id": "100",
"price": 2600,
"gifted": false
}, {
"name": "Sport",
"id": "107",
"price": 2500,
"gifted": false,
"swappableProducts": [{
"name": "Movies",
"id": "105",
"price": 2000,
"gifted": false
}]
}]
},
"extrasBundle": {
"id": "131",
"name": "Optional Extras - MUTV (Sports), LFCTV (Sports), Chelsea TV (Sports)",
"products": [{
"name": "MUTV (Sports)",
"id": "665",
"price": 0,
"gifted": false
}, {
"name": "LFCTV (Sports)",
"id": "666",
"price": 0,
"gifted": false
}, {
"name": "Chelsea TV (Sports)",
"id": "667",
"price": 0,
"gifted": false
}]
}
}
}
console.log(_.get(sampleObject, 'existing.primaryBundle.products'));
The main reason why it returns an error is because existing is not a global scoped object, you have to assign object to some variable like const obj = {...} and then pass the parameter to _pick method as obj.existing, yet I don't see a reason to use lodash in here, you can just reference the path to that object directly.

Unrecognized expression

I have the following json output from a webservice:
[
{
"subCategories": [
{
"subCategories": [],
"menuItems": [],
"id": 2,
"title": "First Course",
"type": "Menu Section",
"categoryID": 9,
"isActive": true,
"orderIndex": 7
}, {
"subCategories": [],
"menuItems": [
{
"id": 0,
"price": 30,
"title": "Meat",
"ingredients": "Bread, Pate, Cilantro, Turkey.",
"cookingTimeInMinutes": 6,
"isActive": true,
"picture": "",
"categoryID": 3,
"orderIndex": 2
}],
"id": 3,
"title": "Banh Mi",
"type": "Food Item",
"categoryID": 9,
"isActive": true,
"orderIndex": 1
}],
"menuItems": [
{
"id": 1,
"price": 1,
"title": "Soup",
"ingredients": "Water, Good Stuffs, Noodles.",
"cookingTimeInMinutes": 10,
"isActive": true,
"picture": "",
"categoryID": 9,
"orderIndex": 4
}, {
"id": 3,
"price": 12,
"title": "Egg Sandwich",
"ingredients": "Egg, Sandwich",
"cookingTimeInMinutes": 6,
"isActive": true,
"picture": "",
"categoryID": 9,
"orderIndex": 3
}],
"id": 9,
"title": "Lunch",
"type": "Menu Section",
"categoryID": null,
"isActive": true,
"orderIndex": 0
}, {
"subCategories": [],
"menuItems": [],
"id": 7,
"title": "Snack",
"type": "Menu Section",
"categoryID": null,
"isActive": true,
"orderIndex": 8
}, {
"subCategories": [],
"menuItems": [],
"id": 6,
"title": "First Course",
"type": "Menu Section",
"categoryID": null,
"isActive": true,
"orderIndex": 5
}, {
"subCategories": [],
"menuItems": [
{
"id": 2,
"price": 3,
"title": "Salad",
"ingredients": "Veggies",
"cookingTimeInMinutes": 5,
"isActive": true,
"picture": "",
"categoryID": null,
"orderIndex": 9
}],
"id": -1,
"title": "Other",
"type": "Menu Section",
"categoryID": null,
"isActive": true,
"orderIndex": 1000
}]
And I have the following javascript snippet that is supposed to iterate over mentioned json and turn it into divs:
<script type="text/javascript">
/* wait until the document has finished loading before loading
* the rest of the content
*/
$(document).ready(function(){
function divifyCategory(containerID, gingerWebCategory){
$('#' + containerID).append(
$('<div class="category" id="' + gingerWebCategory.id + '">' + gingerWebCategory.title + '</div>')
);
for(menuItem in gingerWebCategory.menuItems){
$('.category#' + gingerWebCategory.id).append(
$('<div class="menuItem" id="' + menuItem.id + '">' + menuItem.title + '</div>')
);
}
}
// load menu from web service
$.get('http://localhost:50730/GingerWeb.asmx/getMenu', function(data){
var data = eval(data);
for(var i=0; i<data.length; i++){
divifyCategory(data[i]);
}
});
});
</script>
Any idea on why I get this error message in Chrome:
Uncaught Error: Syntax error, unrecognized expression: #[object
Object]
?
Your json object is an array of objects. When you pass data[i], you are passing the first element in the array, an object, and treating it like a string (containerID). You need to get the ID from the object you're passing.
I suppose datais json string mentioned at the very beginning of the post. data is an array of objects. So there
for(var i=0; i<data.length; i++){
divifyCategory(data[i]);
}
object has been passed to function divifyCategory which expects string as the first parameter. And that parameter is used like string there
$('#' + containerID)
in the runtime you get $('#[object Object]'). It is unxpected situation.
I hope it helps.

Categories