How to get another context path in factory method? - javascript

Let's imagine that we have sap.m.UploadCollection and we bind the data to this collection which is done like this:
bind: function () {
this._oUploadCollection.bindAggregation("items", {
path: "/attachments",
factory: jQuery.proxy(this._bindUploadCollectionItem, this)
});
},
The example of the binding data is here:
{
"attachments": [
{
"size": 123,
"filename": "pdf.pdf",
"id": "pdfId"
},
{
"size": 440,
"filename": "text.txt",
"id": "textId"
}
],
"source":"personWhoAddedAttachments"
}
So, in _bindUploadCollectionItem I successfully can get size, filename and id by oContext.getProperty("nameOfParameter"), but cannot get source:
_bindUploadCollectionItem: function (sID, oContext) {
return new sap.m.UploadCollectionItem({
"id": oContext.getProperty("id"),
"fileName": oContext.getProperty("filename"),
"attributes": [
{
"title": "author",
"text": oContext.getProperty("../source") // <- problem
}]
});
},
So, because I bind attachments it is kind of clear that I could not get source, but how to reach it if I need it?

It depends a little on what property of the model you want to get to. If it is really like you described it and the target property is in the /source absolute model path, then the easiest way of getting it inside the factory function is by using: oContext.getModel().getProperty("/source").
If you need something which is inside a collection (and somehow depends on the current context), you can achieve an effect similar to the .. path construct that you tried by using something along the lines:
var sPath = oContext.getPath(),
sParent = sPath.substring(0, sPath.lastIndexOf("/")),
sText = oContext.getModel().getProperty(sParent + "/source");
return new sap.m.UploadCollectionItem({
"id": oContext.getProperty("id"),
"fileName": oContext.getProperty("filename"),
"attributes": [{
"title": "author",
"text": sText
}]
});
You basically obtain the parent object path by searching for the last / inside the path. You can apply this repeatedly (or use a split, pop some elements, followed by a join) to get to the ancestors (e.g. parent of parent).

Related

How to access an array of objects with tooltip.format() from anychart.js

I am having trouble trying to present an array of objects on the tooltip of an Anychart.js map. I understand that we can access the dataset by doing something like: %[name of property in data set]. My data set has the following form:
{
"country": "Austria",
"id": "AT",
"continent": "Europe",
"songs": [
{
"rank": 33,
"title": "Stuck with U (with Justin Bieber)",
"artists": "Ariana Grande, Justin Bieber",
"album": "Stuck with U",
"explicit": 0,
"duration": "3:48"},
{
"rank": 34,
"title": "Late Night",
"artists": "Luciano",
"album": "Late Night",
"explicit": 0,
"duration": "3:20"
},
... more objects
]
}
}
If I wanted to access the Country property I would simply add it to the tooltip by doing:
tooltip.format("Country: " + {%country});
The issue is when trying to access an array of objects, I have tried different variations and none of them worked. Trying to show the title of every song:
tooltip.format({%songs}.{%title});
tooltip.format({%songs.%title});
tooltip.format({%songs}[{%title}]);
I also saw in the documentation that we can send a function as argument so I tried the following where I would concatenate every title of the collection but did not succeed either:
tooltip.format(function() {
let concatenated = '';
this.songs.forEach(song => {
concatenated += song + ' ';
});
return concatenated;
});
I would really appreciate your help guys.
String tokens do not support nested objects/properties. But you can use the callback function of the formatted to get access to songs. The context prototype includes getData() method provides that. Like this:
series.tooltip().format(function() {
console.log(this.getData('songs'));
return 'tooltip';
});
For details, check the live sample we prepared.
In case any one else is looking for a solution to this answer. I figured out how to loop through an embed array, and call on specific information.
chart.edges().tooltip().format(function () {
var format = ''
var songs = this.getData('songs');
songs.forEach(function (data, builtin, dom) {
format = '<p>'+data['title']+' by '+data['artists']+' </span></p>' + format
});
console.log(format)
return format
});

How to access the right json value that is located through an array?

I'm currently using the fixture file to make sure it will be easier to call the right value.
cy.fixture('latestLead.json').then(function (lead) {
this.lead = lead
})
My son file is the following:
{
"status": 0,
"result": {
"totalSize": 1,
"done": true,
"records": [
{
"attributes": {
"type": "Lead",
"url": "/services/data/v51.0/sobjects/Lead/111111111"
},
"Id": "111111111",
"Name": "Andres Latest Test"
}
]
}
}
The way that I'm trying to get the right value is the following:
cy.get(".gLFyf").type(this.lead.result.records.Id)
I'm able to get totalSize or done from the result object, but I'm not able to get any other value higher than that object. How can I get the Id value from the records Array?
You can access an array item (in your case it's the object) using the index position (in your case it's zero)
cy.get(".gLFyf").type(this.lead.result.records[0].Id)
try this
cy.get(".gLFyf").type(this.lead.result.records[0].Id)

Getting value of a nested object in JSON

I want to get the req1 value in the JSON below, programatically.Here RequestTypeItem can be changed as well, so it is not fixed. Else I could have navigated it using object.subobject
I was able to navigate till slots using
var b = JSON.parse("{ .... }");
b.request.intent.slots.RequestTypeItem.value
But I can navigate further programatically.
{"request": {
"locale": "en-US",
"timestamp": "2016-09-25T00:36:14Z",
"type": {
"name": "request",
"slots": {
"RequestTypeItem": {
"name": "RequestTypeItem",
"value": "req1"
}
}
}
}
}
In your JSON your request does not have a property of intent, it does have a property type, so you then you can access the property you want with
b.request.type.slots.RequestTypeItem.value
JSFiddle: https://jsfiddle.net/9cexbn54/
Edit: After reading your question again, maybe this is what you want:
// loop through all properties on the slots object
for (var i in b.request.type.slots) {
if (b.request.type.slots.hasOwnProperty(i)) { // make sure it is a property belonging directly to slots, and not "inherited" from the prototype chain
if (b.request.type.slots[i].value) { // make sure that the sub-property of slots has a value property
document.getElementById("output").innerHTML = b.request.type.slots[i].value;
break; // break out of the loop after getting a value
}
}
}
Here I loop through all the properties on slots, checking that the property does indeed belong to slots, and that it has value property.
JSFiddle: https://jsfiddle.net/9cexbn54/1/
I had given a link which some of you found it not useful.
Here is what would get to req1:
$data=#'
[{"request": {
"locale": "en-US",
"timestamp": "2016-09-25T00:36:14Z",
"type": {
"name": "request",
"slots": {
"RequestTypeItem": {
"name": "RequestTypeItem",
"value": "req1"
}
}
}
}
}]
'#
$json=ConvertFrom-Json $data
$json.request.type.slots.RequestTypeItem.value

How to use "this" keyword inside array in javascript?

Here I have an array which consists of n number of objects which are similar to this.
var views = [
{
id: "chart-0",
datasource: "",
type: "batch",
context: "/analytics/device/stats/",
schema: [
{
"metadata": {
"names": [""],
"types": [""]
}
}
],
columns: [
{
"name": "month",
"label": "month",
"type": "linear",
},
{
"name": "minValue",
"label": "minValue",
"type": "linear"
},
{
"name": "maxValue",
"label": "maxValue",
"type": "linear",
"axis": "y"
},
{
"name": "time",
"label": "time",
"type": "time",
"axis": "x"
},
],
callbacks: [
{
type: "click",
callback: function() {}
}
],
data: function() {
var COLUMNS = views[0].columns;
}
}
];
I want to access some of the fields inside data function. I can access id, datasource simply this.id or this.datasource. How to access columns inside data function using this keyword instead of views[0].columns
The only way I know that you can use the this key word to assign id, distance, or any other property would be to pass the data into a function.
// create a function and pass in a reference to the views array and specify the objects index you want to operate on.
function chanceProperty( views[0]) {
var currentColumns = this.columns; // gives you a reference to the objects columns array. "This" is a reference to the object that was passed in.
// you can then do your operations on the properties in that array either with a loop or by specifically targeting an object.
currentColumns[1].name = "myNewMinValue";
// or
currentColumns.forEach( function(val, idx) {
currentColumns[idx].name = "allTheSame";
});
}
update
I thin I see what you are trying to do. You want pass some of your views properties to your data function. You don't need "this" for that. You can just pass the properties you want to the data function.
data: function(id, dataSource, columns) {
var COLUMNS = views[0].columns;
}
You can use:
data: function() {
var COLUMNS = this.columns;
return COLUMNS;
}
And you will be able to access columns inside data function:
views[0].data();
Using this needs care. Well you can access views[0].columns by saying this.columns but under two conditions.
You must call the function like views[0].data(); and only then the this in the data function will refer to the views object. In other words if you might like to pass views[0].data as a callback, you better be careful because if you do like doStg(arg1, arg2, views[0].data) then this will no longer refer to the views[0] object but to the global or window scope. So you must pass callbacks like doStg(arg1, arg2, function(){views[0].data})
Somehow instead of conventional method if you would like to define views[0].data as an arrow function, then forget about using this. Since then this would only refer to the limited scope it resides in which is the function's own scope (not even views[0] object)

Backbone: Making Collections out of JSON attributes advice, and making things better

Up until now I've been using .get() and _.clone() on the array attributes then making my object up before setting the model but this feels completely wrong and I'm not sure how to improve upon this. I feel the array attributes should be transformed into collections but 1) I'm not sure how to do this and 2) I'm not sure of the real benefits compared to my current approach. Can anyone help me improve on my approach? Also note, the POST object needs to be created to be sent via AJAX to a non RESTful service
Example model:
{
"id": 1,
"name": "Joe Bloggs",
"teams": [],
"ageGroups": [],
"categories": []
}
Example of how my data should look when posting back to server
{
"id": 1,
"name": "Joe Bloggs",
"teams": [
{
"id": 123,
"name": "Team One",
"location": "UK"
}, {
"id": 321,
"name": "Team Two",
"location": "USA"
}
],
"ageGroups": ["16", "18", "21"],
"categories": [
{
"id": 45,
"name": "Category One"
}, {
"id": 65,
"name": "Category Two"
}
]
}
A very stripped down example:
var myView = new View({
addToCategory: function() {
var categories = _.clone(this.model.get('categories'));
// Grab values I need from user input...
var categoryDetails = {
"id": userId,
"name": userName
};
this.model.set({
categories: categoryDetails
});
},
addToAgeGroups: function() {
var ageGroups = _.clone(this.model.get('ageGroups'));
// Grab my age group via user input ...
ageGroups.push(newAgeGroup);
this.model.set({
ageGroups: ageGroups
});
}
});
Backbone (intentionally?) does not handle nested data particularly well. After some experience I've resisted the urge to make my Model have an attribute on it that is a Collection, etc. It generally makes things more confusing for little benefit.
I suggest making your Models smarter to handle the array attributes, moving some of the logic in your View into the Model itself. If you really think some parts of your application would like to treat that data as a full-blown Collection, have the Model handle that internally too.
For instance:
var MyModel = Backbone.Model.extend({
getCategories: function() {
if (!this._categoriesCollection) {
var categories = this.get('categories');
this._categoriesCollection = new Backbone.Collection(categories);
}
return this._categoriesCollection;
}
addCategory: function(categoryDetails) {
var currentCategories = this.getCategories();
currentCategories.add(categoryDetails);
}
});
Caching the result of getCategories() means you can ensure there is only ever one instance of the collection of categories. You can add more methods to handle the Parent/Child relationship within the Model, making him the sole owner of that data.
Handling how to POST the data to server seems like a separate question, but generally I've overridden the Model.sync() method to do that sort of thing.

Categories