I'm trying to add data to the end of an observable array but it's just not working as expected. I bet it is something minor but I just can't get my head around it.
What I am doing:
self.businesses = ko.observableArray();
function Business(business) {
var self = this;
self.BusinessID = ko.observable(business.BusinessID );
self.Type = ko.observable(business.Type);
self.Location = ko.observable(business.Location);
}
/*ajax get array of businesses as follows:
[
{
"$id": "1",
"BusinessID ": 62,
"Type": "Data",
"Location": "Data"
},
{
"$id": "2",
"BusinessID ": 63,
"Type": "Data",
"Location": "Data"
},
{
"$id": "3",
"BusinessID ": 64,
"Type": "Data",
"Location": "Data",
} ]
*/
var mappedBusinesses = $.map(data, function (business) { return new Business(business) });
self.businesses(mappedBusinesses);
This all works as expected and the obersablearray is populated.
However if I go to add another business, it wont work. For example, if I call the ajax that returns this (as newBusiness):
{
"$id": "1",
"BusinessID ": 68,
"Type": "Data",
"Location": "Data"
}
and I do:
self.businesses().push(newBusiness);
It adds to the array as an "Object" not a Business. So I thought I would do:
var bus = $.map(newBusiness, function (business) { return new Business(business) });
self.businesses().push(bus);
But I get the error in the JS console "Uncaught TypeError: Cannot read property 'BusinessID' of null
So I made a new var and added the brackets: [] in and it adds to the observable array but not as a "Business" object but rather as an "Array[1]" object at the end and this doesn't function as per the others. Code as follows:
var newBus = {
BusinessID: newBusiness.BusinessID,
Type: newBusiness.Type,
Location: newBusiness.Location
}
var bus = $.map(newBus, function (business) { return new Business(business) });
self.businesses().push(bus);
As mentioned this adds to the observable array but doesn't actually add as a "business" object but rather as an "array[1]" object.
I bet it's something so basic but just can't get it working!
Argh I knew it would be simple!
It was posting the whole array to the ObservableArray...not just the object.
The fix:
self.businesses.push(newBusiness[0])
Had to add the [0] in to get it to push the actual data into the array, not the object!
Thanks for the answers!
You're evaluating the array with your push:
self.businesses().push(newBusiness);
Observable Arrays have their own array functions, you should just do this (no parens):
self.businesses.push(newBusiness);
See this page: http://knockoutjs.com/documentation/observableArrays.html
Related
I am trying to filter a JavaScript array (JSON array) with the string array, and set it back in itself.
I am using this code (Removed JSON.stringiFy from allRecords,it was just to show the records on console)
var statusFilters = component.get("v.statusFilters");
console.log('statusFilters--->'+statusFilters);
var allRecords = component.get("v.empWrapperList");
console.log('allRecords--->'+allRecords);
var filteredRecords = allRecords.filter(rec => rec.Status__c == statusFilters);
console.log(filteredRecords);
component.set("v.empWrapperList",filteredRecords);`
Here statusFilter is a string array and allRecords is an object array.
Here are the logs from console.
statusFilters--->Paid
ClaimsDemo.js:119 allRecords--->
[
{
"Id": "a1V2x000001K29pEAC",
"Name": "CL-0000004",
"Member__c": "0032x000004bgAkAAI",
"Date_of_Service__c": "2020-06-25",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Void"
},
{
"Id": "a1V2x000001K14OEAS",
"Name": "CL-0000003",
"Member__c": "0032x000004bgAkAAI",
"Billed__c": 22,
"Date_of_Service__c": "2015-09-15",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Denied"
},
{
"Id": "a1V2x000001K14JEAS",
"Name": "CL-0000002",
"Member__c": "0032x000004bgAkAAI",
"Billed__c": 22,
"Date_of_Service__c": "2019-10-16",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Rejected"
},
{
"Id": "a1V2x000001K14EEAS",
"Name": "CL-0000001",
"Member__c": "0032x000004bgAkAAI",
"Billed__c": 22,
"Date_of_Service__c": "2020-06-04",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Paid"
}
]
Actually it is unable to execute this line
var filteredRecords = allRecords.filter(rec => rec.Status__c == statusFilters);
Can you please help.
your first problem is stringifying.filter method is for array.
second problem is that you cant say rec.Status__c === statusFilters statusFiltersis array and Status__c is string. map to array your object array with correct key name and search rec.Status__c in this array. indexOf is a method to find in array
if statusFilters is just array which includes types like
["Void","Denied"]
then
var filteredRecords = allRecords.filter(rec => statusFilters.indexOf(rec.Status__c)>-1);
if statusFilters is an object array like
[ {"Status__c": "Void" }];
then
var filteredRecords = allRecords.filter(rec => ( statusFilters.map(x=>x.Status__c)).indexOf(rec.Status__c)>-1);
Assume I have the following object:
var jsonObj = {
"response":{
"result":{
"status":{
"name": "Eric"
}
}
}
}
And now i'd like to dynamically access a nested property:
jsonKey = "response.result.status.name";
console.log("the status is: " + jsonObj.jsonKey); //I cannot call jsonObj.jsonKey here
Is there any way to achieve this?
You cannot access a deeply nested property as simple as you expect. Instead you need to use the obj[propertyNameAsString] syntax to dive deeper into the response one by one.
This would be one way of getting there:
let response = {
"response": {
"method": "GetStatus",
"module": "Module",
"data": null,
"result": {
"status": {
"name": "Eric"
},
"id": 1
},
"result_code": {
"error_code": 0
}
}
}
let keyString = "response.result.status.name"
let keyArray = keyString.split('.'); // [ "response", "result", "status", "name" ]
var result = response;
for (key of keyArray) {
result = result[key]
}
console.log(result)
Please be aware that this is not failsafe against cases where one of those strings in keyArray does not exist as a property on the preceding object.
You can do like this something['bar']
Where bar is your variable that has been converted to string, in our case:
jsonObj[`${jsonKey}`]
var obj={"firstName":"John","lastName":"Smith","isAlive":true,"age":25,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null};
I want to access the phoneNumbers field
So I use
phone=obj.phoneNumbers;
I get an array but without "phoneNumbers" field.I want to get someting like this:
{
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
},
{
"type": "mobile",
"number": "123 456-7890"
}
]
}
You have to create a new object then
var phone = { "phoneNumbers": obj.phoneNumbers };
You can add that part in:
var phone = {"phoneNumbers" : obj.phoneNumbers};
Although there should be a good reason for doing this (like, need to pass it to an API that expects exactly "x"). A single-property object is about as useful as the value of its single property.
How about making a function and using it for other similar purposes:
function transform (prop, payload) {
return { [prop]: payload };
}
And use it like:
phone = transform('phoneNumbers', obj.phoneNumbers);
I am trying to use underscoreJs to manipulate a JavaScript object and having problems doing so.
Here is my example
var data = {
"label": "SomeName",
"parent": [{
"id": "parentId",
"resources": [{
"name": "ID1NAME",
"calls": [
"user_get", "user2_post", "user3_delete"
]
}, {
"name": "ID2",
"calls": [
"employee1_get", "employee2_delete", "employee3_update"
]
}]
}]
};
var res = _(data).chain().
pluck('parent').
flatten().
findWhere(function(item){
item === "user_get"
}).
value();
console.log(res);
Using an element which is a part of data.parent.calls[] (example : "user_get") I would like to extract its parent object, i.e. data.parent[0].
I tried above but always get undefined. I appreciate any help on this.
One of the problems you're having is your use of _.pluck. If you execute _.pluck over an object, it'll go over the keys of the object trying to retrieve the property you specified as the second argument (in this case, 'parent'). 'label' is a string and 'parent' is an array so thus the array that you get as a result is [undefined, undefined]. The rest will then go wrong.
One solution could be as follows:
function findCallIndexInParent(call, parent) {
return _.chain(parent)
.pluck('resources')
.flatten()
.findIndex(function (obj) {
return _.contains(obj.calls, call);
})
.value();
}
function findCall(call, data) {
var parent = data.parent;
return parent[findCallIndexInParent(call, parent)];
}
console.log(findCall('user_get', data));
findCall is just a convenient method that will pass the parent property of data to findCallIndexInParent (that will retrieve the index where call is) and return the desired object with the parent array.
Lodash (a fork of underscore) provides a method to get the property of an object that would have come really handy in here (sadly, underscore doesn't have it).
The explanation of findCallIndexInParent is as follows:
Chain the parent list
pluck the resources array
As pluck maps, it returns a list of lists so a flatten is needed.
Find the index of the element which calls contains call
Return the value (the index) of the object that contains call within parent.
Here's the fiddle. Hope it helps.
This would seem to do the trick.
function findByCall(data, call) {
return _.find(data.parent, function(parent) { //From data.parent list, find an item that
return _.some(parent.resources, function(resource) {//has such parent.resource that it
return _.includes(resource.calls, call); //includes the searched resource.calls item
});
});
}
//Test
var data = {
"label": "SomeName",
"parent": [{
"id": "parentId",
"resources": [{
"name": "ID1NAME",
"calls": [
"user_get", "user2_post", "user3_delete"
]
}, {
"name": "ID2",
"calls": [
"employee1_get", "employee2_delete", "employee3_update"
]
}]
}]
};
console.log(findByCall(data, 'user_get'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
If I understand correctly, you want to get the index of the element in the parent array which has any resource with the specified call.
data = {
"label": "SomeName",
"parent": [{
"id": "parentId",
"resources": [{
"name": "ID1NAME",
"calls": [
"user_get", "user2_post", "user3_delete"
]
}, {
"name": "ID2",
"calls": [
"employee1_get", "employee2_delete", "employee3_update"
]
}]
}]
}
// find the index of a parent
const index = _.findIndex(data.parent, parent =>
// that has any (some) resources
_.some(parent.resources, resource =>
// that contains 'user_get' call in its calls list
_.contains(resource.calls, 'user_get')
)
)
console.log(index) // 0
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
If you want to find the actual parent object, use find instead of findIndex
If you want to find all parent objects matching this call, use filter instead of findIndex
I'm working with a response from the Webtrends API in Google apps script and I have a JSON/JS object that looks like this:
"data": [
{
"period": "Month",
"start_date": "2013-12",
"end_date": "2013-12",
"attributes": {},
"measures": {
"Visits": 500
},
"SubRows": [
{
"facebook.com": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"google.co.uk": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"newsnow.co.uk": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"No Referrer": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"t.co": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
}
}
]
}
]
What I need to access is the names i.e facebook.com etc... and visit numbers for each of the SubRows.
I'm able to get the visit numbers, but I can't work out how to get the names. Please note the names will change constantly as different sites will send different amounts of traffic each day.
Section of my code at the moment where I get the visit numbers:
for(i in dObj){
var data = dObj[i].SubRows;
var sd = dObj[i].start_date;
var ed = dObj[i].end_date;
if(sd == ed){
var timep = ""+ sd;
}
else{
var timep = ""+ sd + "-" + ed;
}
var subRows = data[0];
Logger.log(subRows);
for(i in subRows){
var row = subRows[i];
var rmeasures = row.measures;
var rvis = rmeasures.Visits;
values = [timep,"",rvis]; //Blank string for where the name of the site would go
}
}
I've tried the following links, but none of them seem to have the answer:
Getting JavaScript object key list
How to access object using dynamic key?
How to access key itself using javascript
How do I access properties of a javascript object if I don't know the names?
I'm just using vanilla google apps script as I don't have any experience with Jquery etc...
Any help would be much appreciated!
I usually use a little helper function that looks like this:
var keyVal = function(o) {
var key = Object.keys(o)[0];
return {"key": key, "val":o[key]};
} ;
This will map an object with a variable key to a key/value object {key:...., val:{}}, which is usually convenient enough to work with.
describe.only ("stack overflow answer", function(){
it ("is should create a key/value pair" , function(){
var res = keyVal( {
"facebook.com": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
}});
res.key.should.equal('facebook.com');
res.val.attributes.should.deep.equal({});
});
Within the loop, the variable i contains the current key. Replacing the empty string with i should give you what you need.
You might also want to look at some of the more functional tools built into Javascript. Some more concise code might also be more explicit:
data.map(function(datum) {
var timep = datum.start_date == datum.end_date ? datum.end_date :
(data.start_date + "-" + datum.end_date);
return datum.SubRows.map(function(subRow) {
return Object.keys(subRow).map(function(key) {
return [timep, key, subRow[key].measures.Visits];
});
});
});
would return an object something like this:
[
[
[
["2013-12", "facebook.com", 100],
["2013-12", "google.co.uk", 100],
["2013-12", "newsnow.co.uk", 100],
["2013-12", "No Referrer", 100],
["2013-12", "t.co", 100 ]
]
]
]
This just uses map and Object.keys to simplify some of what you're doing with explicit loops.