Map nested JSON data to Knockout observableArray - javascript

We have an observableArray in Knockout which include several JSON objects.
Under each JSON object we have an nested array which needs to be observable.
Knockout is not able to observe arrays nested in each JSON object, in the observableArray.
Is it possible to map an array which is already nested in an observableArray?
Here is an example of one JSON object in the observableArray.
Note: We need to make the "attributeValues" array observable.
{
"attribute": {
"id": 6,
"name": "Some attribute name",
"typeID": 5
},
"type": {
"id": 5,
"typeName": "list"
},
"attributeValues": [{
"id": 10,
"attributeID": 6,
"value": "Some attribute value",
"chosen": false
}, {
"id": 11,
"attributeID": 6,
"value": "Another attribute value",
"chosen": false
}, {
"id": 12,
"attributeID": 6,
"value": "Third attribute value",
"chosen": false
}]
}
Here is the code we're using now:
$.ajax({
type: 'GET',
url: '/JsonService',
success: function (data) {
avm.attributes(data.allAttributes);
},
dataType: 'json',
traditional: true
});
function attributeViewModel() {
var self = this;
self.attributes = ko.observableArray([]);
}
var avm = new attributeViewModel();
ko.applyBindings(avm);

One solution would be to define one more constructor function to wrap each item of the attributes array. In this function, you can then define the attributeValues array as observable as illustrated in the following example:
function AttributeValueViewModel (data) {
var self = this;
self.attribute = ko.observable(data.attribute);
self.type = ko.observable(data.type);
self.attributeValues = ko.observableArray(data.attributeValues);
}
function attributeViewModel() {
var self = this;
self.attributes = ko.observableArray([]);
self.addList = function (list) {
ko.utils.arrayForEach(list, function(item) {
self.attributes.push(new AttributeValueViewModel(item));
});
};
}
var avm = new attributeViewModel();
ko.applyBindings(avm);
$.getJSON('url', function (list) { avm.addList(list); });

Related

How to create a json object from another json object using JavaScript?

I am really junior with JavaScript and json, so I have this JSON input, and I need to get all that information in the "properties" object to create a new JSON object with just that information.
I'm using a base code like this one, but this is just returning {}.
exports.step = function(input, fileInput) {
var alert = {
'Properties': input.alert.properties
}
return JSON.stringify(alert, undefined, 1);
};
Original JSON:
"value": {
"id": "12345",
"entity": {
"_integrationDefinitionId": "7a6764",
"_integrationName": "Apple Main",
"_beginOn": "2021-09-01T02:20:06.189Z",
"displayName": "apple-onev",
"_accountIdPartitioned": "12345|12",
"_class": [
"Deployment",
"Group"
],
"_version": 3,
"_integrationClass": [
"CiSSP",
"Infrastructure"
],
"_accountId": "123456",
"_id": "1e234567",
"_key": "arn:aws:autoscaling:us-west-2:83712398:autoScalingGroup:asd1238-20c8-41aa-bcec-12340912341:autoScalingGroupName/awseb-e-juancito-stack-AWSEBAutoScalingGroup-123456",
"_type": [
"aws_autoscaling_group"
],
"_deleted": false,
"_rawDataHashes": "1233456==",
"_integrationInstanceId": "54321",
"_integrationType": "aws",
"_source": "integration",
"_createdOn": "2021-07-19T23:19:19.758Z"
},
"properties": {
"webLink": "https://google.com",
"arn": "name",
"region": "us-west-2",
"name": "JonnyAndTheVibes",
"launchConfigurationName": "OtherName",
"minSize": 1,
"maxSize": 4,
"desiredCapacity": 1,
"defaultCooldown": 360,
"availabilityZones": "us-west-2a",
"LoadBalancerNames": "MoreInfo",
"healthCheckType": "EC2",
"healthCheckGracePeriod": 0,
"instanceIds": "InstanceName",
"subnetIds": "subnet",
"terminationPolicies": "Default",
"newInstancesProtectedFromScaleIn": false,
"serviceLinkedRoleARN": "aMoreInfo",
"tag.Name": "atag",
"tag.application": "othertag",
"tag.aws:cloudformation:logical-id": "moretagsp",
"tag.aws:cloudformation:stack-id": "taggigante",
"tag.aws:cloudformation:stack-name": "ydaleconlostags",
"tag.elasticbeanstalk:environment-id": "seguimosmetiendoletags",
"tag.elasticbeanstalk:environment-name": "tag",
"tag.env": "tag",
"tag.team": "tag",
"accountId": "tag",
"tag.AccountName": "tag",
"tag.Production": true,
"#tag.Production": "​"
}
}
I'm sure that it will be a simple solution.
You appear to be trying to grab properties from the wrong object. It should be value not alert.
const json = '{"value":{"id":"12345","entity":{"_integrationDefinitionId":"7a6764","_integrationName":"Apple Main","_beginOn":"2021-09-01T02:20:06.189Z","displayName":"apple-onev","_accountIdPartitioned":"12345|12","_class":["Deployment","Group"],"_version":3,"_integrationClass":["CiSSP","Infrastructure"],"_accountId":"123456","_id":"1e234567","_key":"arn:aws:autoscaling:us-west-2:83712398:autoScalingGroup:asd1238-20c8-41aa-bcec-12340912341:autoScalingGroupName/awseb-e-juancito-stack-AWSEBAutoScalingGroup-123456","_type":["aws_autoscaling_group"],"_deleted":false,"_rawDataHashes":"1233456==","_integrationInstanceId":"54321","_integrationType":"aws","_source":"integration","_createdOn":"2021-07-19T23:19:19.758Z"},"properties":{"webLink":"https://google.com","arn":"name","region":"us-west-2","name":"JonnyAndTheVibes","launchConfigurationName":"OtherName","minSize":1,"maxSize":4,"desiredCapacity":1,"defaultCooldown":360,"availabilityZones":"us-west-2a","LoadBalancerNames":"MoreInfo","healthCheckType":"EC2","healthCheckGracePeriod":0,"instanceIds":"InstanceName","subnetIds":"subnet","terminationPolicies":"Default","newInstancesProtectedFromScaleIn":false,"serviceLinkedRoleARN":"aMoreInfo","tag.Name":"atag","tag.application":"othertag","tag.aws:cloudformation:logical-id":"moretagsp","tag.aws:cloudformation:stack-id":"taggigante","tag.aws:cloudformation:stack-name":"ydaleconlostags","tag.elasticbeanstalk:environment-id":"seguimosmetiendoletags","tag.elasticbeanstalk:environment-name":"tag","tag.env":"tag","tag.team":"tag","accountId":"tag","tag.AccountName":"tag","tag.Production":true,"#tag.Production":"​"}}}';
function getAlert(dsta) {
// Destructure the properties object from the
// data's value property
const { properties } = data.value;
// Create a new object with it
const alert = { properties };
// Return the string
return JSON.stringify(alert, null, 2);
};
// Parse the JSON
const data = JSON.parse(json);
// Call the function with the parsed data
const alert = getAlert(data);
console.log(alert);
Additional information
Destructuring assignment
use this function :
function assignJsons(...jsons) {
const convertToObject = jsons.map(json => {
return JSON.parse(json)
});
return JSON.stringify(Object.assign(...convertToObject))
}
//test
console.log(assignJsons(`{"name" : "alex", "family" : "mask"}`, `{"family" : "rejest"}`))
if you want a completely new object
var newJsonObject = JSON.parse('{ "properties":'
+ JSON.stringify (origJson.value.properties) + "}");
or
var newJsonObject={"properties":Object.assign ({}, origJson.value.properties)};

How can I avoid options if those options are previously selected in vue js html?

My json data for getting all inventories is
{
"status": true,
"data": [
{ "inv_id": 1, "name": "Arts" },
{ "inv_id": 2, "name": "web" },
{ "inv_id": 3, "name": "mobileapp" },
{ "inv_id": 4, "name": "ws" },
{ "inv_id": 5, "name": "aop" },
{ "inv_id": 6, "name": "bin" },
{ "inv_id": 7, "name": "webs" },
{ "inv_id": 8, "name": "hell" }
]
}
My json data which is selected already by user will be in the following format
{
"data": {
"pid": 109,
"contact": {
"email": "ew98#gmail.com",
"phone": 85998472,
"address": { "country": "India", "state": "Kerala" }
},
"about": "hello how are you",
"is_featured": false,
"avg_rating": 0,
"total_reviews": 0,
"reviews": [],
"inventory": [
{
"item": {
"name": "Arts",
"category": { "name": "Education", "id": 1 },
"id": 1
}
}
],
"review": null
},
"status": true
}
Here arts is already selected, so I need to avoid the same when I am giving an edit option. How can I able to achieve the same.
mounted() {
var self = this
data = {}
data["auth-token"] = this.authType
data["pid"] = this.pid
$.ajax({
url: "http://127.0.0.1:8000/get/post/",
data: data,
type: "POST",
dataType: "json",
success: function(e) {
if (e.status == 1) {
self.inventory = e.data.inventory
data = {}
data["category"] = self.catid
data["cat_id"] = self.catid
$.ajax({
url: "http://127.0.0.1:8000/alpha/get/inventory/",
data: data,
type: "POST",
dataType: "JSON",
success: function(e) {
if (e.status == 1) {
self.inventoryall = e.data
}
},
})
}
},
})
}
I have all inventories in inventoryall[] and inventory that is already added in inventory[].
My html code is
<div class="form-group">
<label>Inventory
<small>(required)</small>
</label>
<select
id="basic"
class="selectpicker"
data-live-search="true"
data-live-search-style="begins"
title="Select Your Subcategory"
v-model="inv" name="inv[]" multiple required="required"
>
<option v-for="sop in inventoryall" v-bind:value="sop.inv_id">{{sop.name}}</option>
</select>
</div>
So, when I display the inventories here, I need to avoid the once that is already selected. Please help me to have a solution.
Here you can use the array filter method:
// filter loops through every item in the array and returns a new array
// if the filter function returns true, the item stays in the new array
// if the filter function returns false, the item is removed
self.inventoryall = self.inventoryall.filter(item => {
// loop through all of the currently selected items
for (const selectedItem of self.inventory) {
// if we find a current item with the same ID as the selected one,
// return false, so we don't keep the item
if (selectedItem.id === item.inv_id) {
return false
}
}
// if we never find an item with a matching ID, return true to keep it
return true
})
Note that this method is only available in browsers that support ES6, so use the polyfill on the MDN page if you need to support older browsers.
Another note, since you're using Vue, this would probably be a good use case for a computed property.

How to hide object property to display using angular ng-model?

I want to hide _id to display on UI using ng-model , I see alot of examples of filtering data using ng-repeat but i did not find angular solution to achieve this task using ng-model.How can hide _id property to display ?
main.html
<div ng-jsoneditor="onLoad" ng-model="obj.data" options="obj.options" ></div>
Ctrl.js
$scope.obj.data = {
"_id": "58a3322bac70c63254ba2a9c",
"name": "MailClass",
"id": "MailTask_1",
"createdBy": "tyuru",
"__v": 0,
"properties": [{
"label": "Java Package Name",
"type": "String",
"editable": true,
"binding": {
"type": "property",
"name": "camunda:class"
},
"$$hashKey": "object:29"
}],
"appliesTo": [
"bpmn:ServiceTask"
]
}
var json = {};
function loadCurrentUserAndTemplate() {
AuthService.getCurrentUser()
.then(function(resp) {
$scope.currentUser = resp.data.id;
// console.log($scope.currentUser);
userTemplate($scope.currentUser);
});
}
loadCurrentUserAndTemplate();
$scope.obj = {
data: json,
options: {
mode: 'tree'
}
};
var privateFields = removePrivateFields($scope.obj.data, ['_id', '__v']);
// add private fields back to $scope.obj.data before POST
var modifiedData = Object.assign({}, $scope.obj.data, privateFields);
function removePrivateFields(obj, props) {
var output = {};
props.forEach(function(prop) {
if (obj.hasOwnProperty(prop)) {
output[prop] = obj[prop];
delete obj[prop];
}
});
return output;
}
function userTemplate(user) {
// console.log('inside template',$scope.currentUser);
templateService.getUserTemplates(user)
.then(function(response) {
// console.log('userTemplate',response.data);
// console.log(response.data.length);
$scope.displayedTemplates = response.data;
if (response.data.length !== 0 && response.data !== null) {
$scope.obj.data = response.data[0];
}
}
you can create a function like removePrivateFields to strip the private fields from original object and attach them back to the modified object before submitting to server
// for testing
var $scope = { obj: {} };
var jsonData = {
"_id": "58a3322bac70c63254ba2a9c",
"name": "MailClass",
"id": "MailTask_1",
"createdBy": "tyuru",
"__v": 0,
"properties": [{
"label": "Java Package Name",
"type": "String",
"editable": true,
"binding": {
"type": "property",
"name": "camunda:class"
},
"$$hashKey": "object:29"
}],
"appliesTo": [
"bpmn:ServiceTask"
]
};
var privateFields = removePrivateFields(jsonData, ['_id', '__v']);
// private fields got removed form actual jsonData
$scope.obj.data = jsonData;
console.log($scope.obj.data);
// once edit
// add private fields back to $scope.obj.data before POST
var modifiedData = Object.assign({}, $scope.obj.data, privateFields);
console.log(modifiedData);
function removePrivateFields(obj, props) {
var output = {};
props.forEach(function(prop) {
if (obj.hasOwnProperty(prop)) {
output[prop] = obj[prop];
delete obj[prop];
}
});
return output;
}
It would be both more performant and along Angular best practices to instead delegate this functionality into your controller or the service fetching the object.
Ideally, you want to perform any object manipulation or formatting within an Angular service, but you could also do it within your controller (probably fine if you're just instantiating your JSON editor with mock data).

How do I loop through this Json object (angularJS)?

I'm trying to loop through "tabs" in the Json object using AngularJS? How can I do it?
var model = {
"$id": "1",
"tabs": [{
"$id": "2",
"id": 2,
"name": "Output",
"layoutId": 1,
"order": 1,
"dashboardId": 1
}, {
"$id": "15",
"id": 3,
"name": "Yield",
"layoutId": 1,
"order": 2,
"dashboardId": 1
}, {
"$id": "24",
"id": 4,
"name": "Trend",
"layoutId": 1,
"order": 3,
"dashboardId": 1
}],
"id": 1,
"name": "Test",
"title": "Test",
"description": "Test Dashboard",
"createDate": "2015-06-08T00:00:00+01:00",
"ownerId": 1,
"enabled": true
};
When I try this, I get "undefined" in the console.
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
not sure what I'm doing wrong?
EDIT:
The data is coming from ASP.Net controller:
$http.get("/Dashboards/GetDashboardData").success(function (data) {
model = data;
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
}).error(function (data) {
console.log("error");
});
I expect that the model is not ready at the time you loop though it. Run the following code with your inspector open - the code you have is correct, but in your case fails because model isn't ready when you run the loop.
If you're loading data asyncronously you'll want to wait until the data is returned, either using a promise or a callback, and the loop through it.
var model = {
"tabs": [{
"name": "Output",
}, {
"name": "Yield",
}, {
"name": "Trend",
}],
};
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Ok I found the answer. It looks like my controller returns Json object as a string, so I have to switch it to object before I can use it as an object.
I have add this line before using model in the loop:
model = JSON.parse(data);
The whole solution with promise (not sure if I need it now):
DataService.getDashboardData().then(function (data) {
model = JSON.parse(data);
angular.forEach(model.tabs, function (tab) {
console.log(tab);
});
});
app.service("DataService", ["$http", "$q", function ($http, $q) {
return {
getDashboardData: function () {
var dfd = $q.defer();
$http.get('/Dashboards/GetDashboardData').success(function (result) {
dfd.resolve(result);
});
return dfd.promise;
}
};
}]);

Knockout combining multiple json data into single vm

I want to combine multiple json data into a single vm. I read that you can map from js into the model multiple times and it should be merging but on my case, it's not. It's replacing the data.
function Item(ID, Name, Description) {
this.ID = ko.observable(ID);
this.Name = ko.observable(Name);
this.Description = ko.observable(Description);
}
var MasterViewModel = {
model: ko.observableArray([])
};
$.getJSON(url, function (response) {
ko.mapping.fromJS(response["TM1.Cube"], Item, MasterViewModel.model);
ko.mapping.fromJS(response["TM1.Dimension"], Item, MasterViewModel.model);
})
ko.applyBindings(MasterViewModel);
And here is my json data
{
"LogicalName": "TM1.Model",
"ID": "12345",
"Name: "Sample",
"TM1.Cube": [
{
"LogicalName": "TM1.Cube",
"ID": "111111",
"Name": Assets"
},
{
"LogicalName": "TM1.Cube",
"ID": "111112",
"Name": Finance"
}
],
"TM1.Dimension": [
{
"LogicalName": "TM1.Dimension",
"ID": "222221",
"Name": Assets"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222222",
"Name": Finance"
}
]
}
and the outcome I expected is like this
{
"LogicalName": "TM1.Cube",
"ID": "111111",
"Name": Assets"
},
{
"LogicalName": "TM1.Cube",
"ID": "111112",
"Name": Finance"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222221",
"Name": KPI"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222222",
"Name": Default"
}
I have added a jsFiddle http://jsfiddle.net/e1ppj3qc/1/
The mapping plugin can take an existing model but I don't believe it will merge data.
For example you could map twice like so:
{one: "yo"}
and
{two: "dawg"}
into the same model and you would now have two observables, one() and two()
But if you was to do this (which you are):
{one: ["yo"]}
and
{one: ["dawg"]}
it will always overwrite the matched properties.
You could instead do the mapping and then simply push into the array that you want to add to like so:
function pushCubs(dataToPush) {
ko.utils.arrayPushAll(MasterViewModel.modelcub, dataToPush());
}
pushCubs(ko.mapping.fromJS(data));
pushCubs(ko.mapping.fromJS(data2));
http://jsfiddle.net/e1ppj3qc/2/

Categories

Resources