How to bind an array to a ListView - javascript

I know how to parse with Json and bind a file like this to a listview:
[
{
"key": "Arthur Schopenhauer",
"numeroFrasi": 3,
"foto" : "images/TEST.jpg",
},
{
"key": "Nietzsche",
"numeroFrasi": 1,
"foto" : "images/TEST.jpg",
},
.........
But I can't understand nor find on Web how to bind just every "frasi" (that is an array) in a file like this:
[
{
"key": "Arthur Schopenhauer",
"numeroFrasi": 3,
"foto" : "images/TEST.jpg",
"frasi": [
"Fras1",
"Frase 2 schopenahuer",
"Frase 3 schopenhahuer"
]
},
{
"key": "Nietzsche",
"numeroFrasi": 1,
"foto" : "images/TEST.jpg",
"frasi": [
"Frase 2 nietzsche",
"Frase 3 nietzsche"
]
},
...............
My Object isn't an array, but it is definied like this form a txt file parsed with Json:
This is the generic definition:
(function () {
"use strict";
var list = new WinJS.Binding.List();
var groupedItems = list.createGrouped(
function groupKeySelector(item) { return item.group.key; },
function groupDataSelector(item) { return item.group; }
);
WinJS.xhr({ url: "/data/frasi.txt" }).then(function (xhr) {
var items = JSON.parse(xhr.responseText);
// Add the items to the WinJS.Binding.List
items.forEach(function (item) {
list.push(item);
});
});
Then this is the specific definition (because when I navigate to my page, I select just an "item", so only one "key, "numeriFrasi", "foto", "frasi":
WinJS.UI.Pages.define("/pages/itemDetail/itemDetail.html", {
ready: function (element, options) {
item = options && options.item ? Data.resolveItemReference(options.item) : Data.items.getAt(0);
"resolveItemReference" gets one item from all the items created

Strip out frasis to an Array first. You can use underscore.js
frasis = YOUROBJECT.map(function(el){return el.frasi;});
frasis = _(frasis).faltten();
Then use it to build your ListView

Related

DynamoDB remap list attribute item on query

Is there a way to transform the output of a DynamoDB query (using doc-client in Lambda) during the query process. Specifically, I wish to extract the first item of a list and put it in a new attribute.
As a simplified example the DynamoDB has the following entries:
{
"Id": 1
"Items": [ "item-1", "item-2", "item-3" ]
},
{
"Id": 2,
"Items": [ "item-x" ]
},
{
"Id": 3,
// "Items" is potentially optional
}
And using the following Lambda function:
// ...
exports.handler = async (event, context) => {
return dynamoDoc.query({
TableName : 'some-table',
Select : 'SPECIFIC_ATTRIBUTES',
KeyConditionExpression : 'Id = :id',
ExpressionAttributeValues : {
':id' : event.Id,
},
ProjectionExpression : `
Id,
Items[0]
`,
}).promise();
};
However this returns a list with items which look like:
"Items": [
{
"Id": 1,
"Items": [
"item-1"
]
},
{
"Id": 2,
"Items": [
"item-x"
]
},
{
"Id": 3
}
]
Is there a way to remap attribute names using some kind of expression, such that I could get the data output in the form of:
Items: [
{
"Id": 1,
"FirstItem: "item-1"
},
{
"Id": 2,
"FirstItem: "item-x"
},
{
"Id": 3
}
]
I am currently using Javascript's array.forEach on the data afterward, however, I am trying to avoid this and would rather leverage DynamoDB for this computation.
No way.
Best practice is just create a helper function like a Repository, the helper function will wrap all query to Dynamodb and returns final object for handler function.
Quick fix, use .map instead of .forEach
exports.handler = async (event, context) => {
const result = await dynamoDoc.query({
TableName: 'some-table',
Select: 'SPECIFIC_ATTRIBUTES',
KeyConditionExpression: 'Id = :id',
ExpressionAttributeValues: {
':id': event.Id,
},
ProjectionExpression: `
Id,
Items[0]
`,
}).promise();
result.Items = result.Items.map((i) => {
return {
Id: i.Id,
FirstItem: i.Items && i.Items.length ? i.Items[0] : undefined,
}
});
return result; // final result
};

Creating Tableau WDC from associative array

I am creating a Tableau Web Data Connector as described in their Getting Started guide HERE.
I have implemented a similar solution previous with data from a basic associative array, but I am having trouble with my current API call.
I make an API call to an external web service that returns a JSON similar to the one listed below (simplified version)(COMMENT simply added for clarity and not part of original code).
{
"status": true,
"employee": {
"id": 123
},
"company": {
"id": 123
},
"job": {
"id": 123,
"job_workflows": [{
"id": 1,
"name": "Start",
"action_value_entered": "Start"
}, {
"id": 2,
"name": "Date",
"action_value_entered": "2017-09-11"
}, {
"id": 3,
"name": "Crew",
"action_value_entered": "Crew 3"
},
**COMMENT** - 17 other unique fields - omitted for brevity
]
}
}
For my requirements, I need to create a new column for each of my JSON job_workflows to display the data in Tableau. I.e.
Column 1 Header = Start
Column 1 value = Start
Column 2 Header = Date Complete
Column 2 value = 2017-09-11
Etc.
My Tableau JavaScript file looks as below:
(function () {
var myConnector = tableau.makeConnector();
myConnector.init = function(initCallback) {
initCallback();
tableau.submit();
};
myConnector.getSchema = function (schemaCallback) {
var cols = [
{ id : "start", alias : "Start", dataType: tableau.dataTypeEnum.string },
{ id : "date", alias : "Date", dataType: tableau.dataTypeEnum.datetime },
{ id : "crew", alias : "Crew", dataType: tableau.dataTypeEnum.string }
];
var tableInfo = {
id : "myData",
alias : "My Data",
columns : cols
};
schemaCallback([tableInfo]);
};
myConnector.getData = function (table, doneCallback) {
$.getJSON("http://some/api/call/data.php", function(response) {
var resp = response; // Response is JSON as described above
var tableData = [];
// Iterate over the JSON object
for (var i = 0, len = feat.length; i < len; i++) {
// not working
tableData.push({
"start": resp.job.job_workflows[i].action_value_entered,
"date": resp.job.job_workflows[i].action_value_entered,
"crew": resp.job.job_workflows[i].action_value_entered
});
}
table.appendRows(tableData);
doneCallback();
});
};
tableau.registerConnector(myConnector);
})();
How do I iterate over the JSON job_workflow and assign each action_value_entered to be a id in my getSchema() function? My current version simply hangs and no values are returned. NO error or warnings thrown.

Javascript strange behavior in Json Object Manipulation

I really can't get my hand around what is happening there and I really think that I should share this with you guys:
I am making a call to my api at '/products' and the response looks something like this in postman:
[
{
"id": 2,
"name": "some_product_name",
"description": "description",
"price": "$120.00",
"firmware_version": "1.0",
"quantity_in_stock": 50,
"selling": true,
"build_version": "1.2",
"category_id": 1,
"available_colors": [
{
"name": "blue",
"in_stock": true,
"picture": {
"type": "Buffer",
"data": []
}
},
{
"name": "black",
"in_stock": true,
"picture": null
},
{
"name": "silver",
"in_stock": true,
"picture": {
"type": "Buffer",
"data": []
}
}
]
}
]
Now what I am trying to do here is to create a new object called products_showcase that has one entry per product color, with the same informations except for the available_colors property, replaced by the color object:
$scope.initModel = function() {
$http({
method: 'GET',
url: '/products'
}).then(function(resp) {
console.log(resp.data);
$scope.products = resp.data;
$scope.products.forEach((item, index, array) => {
item.available_colors.forEach((color, index, array) => {
var product = item;
product.color = {};
product.color = color;
delete product['available_colors'];
$scope.products_showcase.push(product);
});
});
}, function(error) {
$scope.error = error;
});
};
But then, something really strange is happening:
The available_colors property gets deleted also in the response object, that I did not touch in the code in any way.
The color property gets added to the response object too.
The products_showcase is an array containing the same object 3 times with the color property equal to the firs color of the $scope.products.available_colors object i am iterating through
Javascript won't create new object when you assign it to a variable. You can use Object.create function to create a new object
from existing one.
$scope.initModel = function() {
$http({
method: 'GET',
url: '/products'
}).then(function(resp) {
console.log(resp.data);
$scope.products = Object.create(resp.data);
$scope.products.forEach((item, index, array) => {
item.available_colors.forEach((color, index, array) => {
var product = Object.create(item);
product.color = {};
product.color = color;
delete product['available_colors'];
$scope.products_showcase.push(product);
});
});
}, function(error) {
$scope.error = error;
});
};
Javascript assignment operator doesn't apparently create a new instance of the object for the new variable, it simply creates a pointer to the memory address of the 'father' object.
Example code:
var object = {property: 'myProp'};
console.log(object);
{property: 'myProp'}
var newObj = object;
newObj.newProperty = 'myNewProp';
console.log(object);
{property: 'myProp', newProperty: 'myNewProp'}
To create a new instance of the object we have to use the Object.create() method.

Loading nested JSON array with knockout js

I am trying to load a form where I can update the existing data from the database.
My Object has one nested array in inside each element in that array also have a nested array.
It looks like the following
{
"Id": 13,
"Name": "Category 1",
"DeliveryOptions":
[
{
"Id": 15,
"DeliveryCategoryId": 13,
"Name": "Option 1.-1",
"DeliveryBreakPoints":
[
{
"Id": 19,
"DeliveryOptionId": 15,
"Start": 0,
"End": 10,
"Flat": 1,
"Variable": 2,
"Delete": false
}
]
},
{
"Id": 16,
"DeliveryCategoryId": 13,
"Name": "Option1-2",
"DeliveryBreakPoints":
[
{
"Id": 20,
"DeliveryOptionId": 16,
"Start": 0,
"End": null,
"Flat": 1,
"Variable": 3,
"Delete": false
}
]
}
]
}
You can see inside the object there's an array called "DeliveryOptions" and each "DeliveryOptions" array has another array called "DeliveryBreakPoints"
I have configured knockout js model as the following
function DeliveryCategory(id, name, options) {
this.Id = id;
this.Name = name;
this.DeliveryOptions = ko.observableArray(options);
}
function DeliveryOption(id, name, breakpoint) {
bpIdCounter = 0;
this.Id = id;
this.Name = name;
this.DeliveryBreakPoints = ko.observableArray(breakpoint);
this.addDeliveryBreakPoint = function (option) {
option.DeliveryBreakPoints.push(new DeliveryBreakPoint(bpIdCounter++));
}
}
function DeliveryBreakPoint(id, start, end, flat, variable) {
var self = this;
self.Id = id;
self.Start = start;
self.End = end;
self.Flat = flat;
self.Variable = variable;
}
I am passing parameters (such as id and name ...) as this code is also used to create new object.. However I am not sure if this is preventing it to get the existing model binded.
I also created a view model which looks like this
function DeliveryCategoryViewModel(model) {
var self = this;
if (model.Id > 0) {
self.DeliveryCategory = ko.observable(model);
} else {
self.DeliveryCategory = ko.observable(new DeliveryCategory(null, "", [new DeliveryOption(null, "")]));
}
self.addDeliveryOption = function () {
self.DeliveryCategory().DeliveryOptions.push(new DeliveryOption(null, "", [new DeliveryBreakPoint(null,"0","","","","")]));
}
self.removeDeliveryOption = function (option) {
self.DeliveryCategory().DeliveryOptions.remove(option);
}
self.removeDeliveryBreakPoint = function (option, breakPoint) {
option.DeliveryBreakPoints.remove(breakPoint);
}
self.onSubmit = function () {
$.ajax({
url: "CreateDeliveryCategory",
type: "POST",
data: ko.toJSON(self),
async: true,
contentType: "application/json"
}).success(function (data) {
window.location = data;
}).error(function(error){
alert(error);
})
}
}
This code is also used when I create a new delivery category from the scratch which works fine(this is why there is a check for "model.Id > 0"). It doesn't bind the model if model.id > 0. It only displays Delivery Category name and the first Delivery Option name correctly(even there are two delivery options) and the rest is just broken.
Can anyone please pinpoint what is going on?

compound index/searching on child array

Based on the data below, I'm looking to do something like "find block 1 where the parent objects name is 'Panel'"
So, I tried setting up a compound index like this:
objStore.createIndex('by_name_and_block', ['Name', 'blocks.Name']);
And then calling it (sort-of) like this:
var index = objStore.index("by_name_and_block");
var request = index.get("Panel", "1");
// I've also tried:
// var request = index.get(["Panel","1"]);
...
But this doesn't work. Is there a way to set up this compound index in indexeddb?
Sample data:
[
{
Name: "Post",
blocks: [
{
Name:"1",
Arrays:[]
},
{
Name:"2",
Arrays:[]
},
]
},
{
Name: "Panel",
blocks: [
{
Name:"1",
Arrays:[]
},
{
Name:"2",
Arrays:[]
},
]
},
]
Your data is not able to index with current specification. See steps for extracting key from keyPath. Notice that object is not valid key value in array key path.
In v2, you will be able to use with index function expression.
Currently, you will have to generate extra variable before you persist into the database and remove it after retrieval. Use multiEntry index without compound index.
Is this script that what you want?
var obj = [
{
Name: "Post",
blocks: [
{
Name:"1",
Arrays:[]
},
{
Name:"2",
Arrays:[]
},
]
},
{
Name: "Panel",
blocks: [
{
Name:"1",
Arrays:[]
},
{
Name:"2",
Arrays:[]
},
]
},
];
function getBlockByName(objName, index){
for(var i = 0; i < obj.length; i++){
if(obj[i].Name == objName)
return obj[i].blocks[index];
}
return false;
}
//Index starting from 0
console.log(getBlockByName("Panel", 1));
//Will return {Name:"2", Arrays:[]} object

Categories