Pushing data from json object to ko.obsrvablearray() - javascript

I want to push some field from json object that look like that
{
"type": "tasks",
"levels": 3,
"links": [
{
....
}
],
"assignedDate": "2017-08-02 16:03:36",
"number": 200612,
"priority": 3,
"createdDate": "2017-08-02 16:03:36",
"state": "ASSIGNED",
"ownerRole": "LoanApplication.Process Owner",
"processName": "LoanProcess",
.
.
.
}
in ko.observableArray. this is my JS code (i am using oracle jet )
define(['ojs/ojcore', 'knockout', 'ojs/ojtable'], function (oj, ko) {
function homeContentViewModel() {
var self = this;
self.data = ko.observableArray();
$.getJSON("http://localhost:8085/get/bpm").
then(function (taches) {
$.each(taches, function () {
self.data.push({
title: this.type,
releaseYear: this.levels,
director: this.title
});
});
});
self.dataSource = new oj.ArrayTableDataSource(
self.data,
{idAttribute: 'title'}
);
}
return homeContentViewModel;
});
ps: when i change the JSON object to a JSON array it work
Any help is appreciated.

function Model(opt_data) {
var data = opt_data || {};
var self = this;
self.taches = ko.observableArray([]); // with ([])
for (var i = 0; i < data.taches.length; i++) {
var tache = new Tache(data.taches[i]);
self.taches.push(tache);
}
}
function Tache(opt_data) {
var data = opt_data || {};
var self = this;
self.title = ko.observable(data.type || "");
self.releaseYear = ko.observable(data.levels || "");
self.director = ko.observable(data.title || "");
}
var vm = new Model(dataJson); //Your json with some data
ko.applyBindings(vm);

Thanks to #user3297291 this one worked
define(['ojs/ojcore', 'knockout', 'ojs/ojtable'], function (oj, ko) {
function homeContentViewModel() {
var self = this;
self.data = ko.observableArray();
$.getJSON("http://localhost:8085/get/bpm").
then(function (taches) {
self.data.push({
title: this.type,
releaseYear: this.levels,
director: this.title
});
});
self.dataSource = new oj.ArrayTableDataSource(
self.data,
{idAttribute: 'title'}
);
}
return homeContentViewModel;
});

Related

Find all in-between connections from a node to other in jsPlumb

In jsPlumb, I am trying to get the full path between 2 nodes as an array with a single query even if there is multiple nodes in between source and destination. I am currently doing it with a BFS algorithm because I couldn't find anything like that in the documentation the code is
getPath: function (sourceId, targetId) {
var me = this;
var addNode = function addNode(graph, node) {
graph.set(node, {
in: new Set(),
out: new Set()
});
};
var connectNodes = function connectNodes(graph, sourceId, targetId) {
graph.get(sourceId).out.add(targetId);
graph.get(targetId).in.add(sourceId);
};
var buildGraphFromEdges = function buildGraphFromEdges(edges) {
return edges.reduce(function (graph, {
sourceId,
targetId
}) {
if (!graph.has(sourceId)) {
addNode(graph, sourceId);
}
if (!graph.has(targetId)) {
addNode(graph, targetId);
}
connectNodes(graph, sourceId, targetId);
return graph;
}, new Map());
};
var buildPath = function buildPath(targetId, path) {
var result = [];
while (path.has(targetId)) {
var sourceId = path.get(targetId);
result.push({
sourceId,
targetId
});
targetId = sourceId;
}
return result.reverse();
};
var findPath = function findPath(sourceId, targetId, graph) {
if (!graph.has(sourceId)) {
throw new Error('Unknown sourceId.');
}
if (!graph.has(targetId)) {
throw new Error('Unknown targetId.');
}
var queue = [sourceId];
var visited = new Set();
var path = new Map();
while (queue.length > 0) {
var start = queue.shift();
if (start === targetId) {
return buildPath(start, path);
}
for (var next of graph.get(start).out) {
if (visited.has(next)) {
continue;
}
if (!queue.includes(next)) {
path.set(next, start);
queue.push(next);
}
}
visited.add(start);
}
return null;
};
var graph = buildGraphFromEdges(me.jsPlumbContainer.getAllConnections());
var resultPath = findPath(sourceId, targetId, graph);
return resultPath;}
Is there a much better way to implement this ?
example array for my configuration is:
var connections =[
{
"sourceId": "l1",
"targetId": "l2"
},
{
"sourceId": "l2",
"targetId": "l4"
},
{
"sourceId": "l2",
"targetId": "l3"
},
{
"sourceId": "l4",
"targetId": "l5"
}, ]

How to inherit Odoo's StatementModel class in account.ReconciliationModel?

According to file account/static/src/js/reconciliation_model.js in Odoo module, there is an object assignment :
var StatementModel = BasicModel.extend({
...
...
...
load: function (context) {
var self = this;
var statement_ids = context.statement_ids;
if (!statement_ids) {
return $.when();
}
this.context = context;
var def_statement = this._rpc({
model: 'account.bank.statement',
method: 'reconciliation_widget_preprocess',
args: [statement_ids],
})
.then(function (statement) {
self.statement = statement;
self.bank_statement_id = statement_ids.length === 1 ? {id: statement_ids[0], display_name: statement.statement_name} : false;
self.valuenow = 0;
self.valuemax = statement.st_lines_ids.length;
self.context.journal_id = statement.journal_id;
_.each(statement.st_lines_ids, function (id) {
self.lines[_.uniqueId('rline')] = {
id: id,
reconciled: false,
mode: 'inactive',
mv_lines: [],
offset: 0,
filter: "",
reconciliation_proposition: [],
reconcileModels: [],
};
});
});
var def_reconcileModel = this._rpc({
model: 'account.reconcile.model',
method: 'search_read',
})
.then(function (reconcileModels) {
self.reconcileModels = reconcileModels;
});
var def_account = this._rpc({
model: 'account.account',
method: 'search_read',
fields: ['code'],
})
.then(function (accounts) {
self.accounts = _.object(_.pluck(accounts, 'id'), _.pluck(accounts, 'code'));
});
return $.when(def_statement, def_reconcileModel, def_account).then(function () {
_.each(self.lines, function (line) {
line.reconcileModels = self.reconcileModels;
});
var ids = _.pluck(self.lines, 'id');
ids = ids.splice(0, self.defaultDisplayQty);
self.pagerIndex = ids.length;
return self.loadData(ids, []);
});
},
...
...
...
});
I want to change the statement :
var def_statement = this._rpc({
model: 'account.bank.statement',
method: 'reconciliation_widget_preprocess',
args: [statement_ids],
})
to
var def_statement = this._rpc({
model: 'account.bank.statement',
method: 'reconciliation_widget_preprocess_with_line',
args: [statement_ids, statement_line_ids],
})
My code is something like this :
odoo.define('my_accounting.ReconciliationModel', function (require) {
"use strict";
var BasicModel = require('web.BasicModel');
var field_utils = require('web.field_utils');
var utils = require('web.utils');
var session = require('web.session');
var CrashManager = require('web.CrashManager');
var core = require('web.core');
var _t = core._t;
var ReconciliationModel = require('account.ReconciliationModel');
var StatementModel = ReconciliationModel.StatementModel;
var MyStatementModel = StatementModel.extend({
load: function (context) {
var self = this;
var statement_ids = context.statement_ids;
if (!statement_ids) {
return $.when();
}
var statement_line_ids = context.statement_line_ids;
this.context = context;
var def_statement = this._rpc({
model: 'account.bank.statement',
method: 'reconciliation_widget_preprocess_with_line',
args: [statement_ids, statement_line_ids],
})
.then(function (statement) {
self.statement = statement;
self.bank_statement_id = statement_ids.length === 1 ? {id: statement_ids[0], display_name: statement.statement_name} : false;
self.valuenow = 0;
self.valuemax = statement.st_lines_ids.length;
self.context.journal_id = statement.journal_id;
_.each(statement.st_lines_ids, function (id) {
self.lines[_.uniqueId('rline')] = {
id: id,
reconciled: false,
mode: 'inactive',
mv_lines: [],
offset: 0,
filter: "",
reconciliation_proposition: [],
reconcileModels: [],
};
});
});
var domainReconcile = [];
if (context && context.company_ids) {
domainReconcile.push(['company_id', 'in', context.company_ids]);
}
if (context && context.active_model === 'account.journal' && context.active_ids) {
domainReconcile.push(['journal_id', 'in', [false].concat(context.active_ids)]);
}
var def_reconcileModel = this._rpc({
model: 'account.reconcile.model',
method: 'search_read',
domain: domainReconcile,
})
.then(function (reconcileModels) {
self.reconcileModels = reconcileModels;
});
var def_account = this._rpc({
model: 'account.account',
method: 'search_read',
fields: ['code'],
})
.then(function (accounts) {
self.accounts = _.object(_.pluck(accounts, 'id'), _.pluck(accounts, 'code'));
});
return $.when(def_statement, def_reconcileModel, def_account).then(function () {
_.each(self.lines, function (line) {
line.reconcileModels = self.reconcileModels;
});
var ids = _.pluck(self.lines, 'id');
ids = ids.splice(0, self.defaultDisplayQty);
self.pagerIndex = ids.length;
return self.loadData(ids, []);
});
}
});
});
It not working well. I've performed upgrade my module and still call reconciliation_widget_preprocess method instead of reconciliation_widget_preprocess_with_line in my Odoo module.
Can someone tell me what I missing? I'm using Odoo 11 community edition. I thanks to you for any clue.
You need to use include method when Patching an existing class.
var Hamster = require('web.Hamster');
Hamster.include({
sleep: function () {
this._super.apply(this, arguments);
console.log('zzzz');
},
});

angular Chart data-pushing from another javascript

I have an array in data_controller.js and i wanted my main.js, where I edit my angular chart there, to be able to fetch the array. Any specific way on doing this?
Data_Controller.js:
/*global angular*/
var app = angular.module('statisticsApp', [chart.js]).controller('myCtrl',
function ($scope, $http) {
"use strict";
return $http({
method : "POST",
url : "GatewayAPI.php",
}).then(function mySuccess(response) {
$scope.records = response.data;
var mydata,myJSON,myresult,myjava, myobj;
var i;
var Result;
var chartResultTemp = [];
var chartResultph = [];
var chartResultHum = [];
var resultType = [];
for(i=0; i<72;i++)
{
//storing data
mydata = $scope.records.data[i];
//retrieving data
myobj = mydata.data.substring(3,4);
resultType = mydata.data.substring(3, 4);
if(resultType === "A") {
chartResultTemp.push([mydata.data.substring(6,9)]);
} else if (resultType ==="B") {
chartResultph.push([mydata.data.substring(6, 9)]);
} else {
chartResultHum.push([mydata.data.substring(6, 9)]);
};
$scope.test=Result; //change to array
$scope.test2=chartResultTemp;
$scope.test3 = resultType;
$scope.test4 = chartResultph;
$scope.test5 = chartResultHum;
console.log(Result);
console.log(resultType);
}
$scope.gotTemp = false;
$scope.gotHumidity = false;
$scope.getSoilMoisture = false;
});
});
main.js:
var app = angular.module("statisticsApp", ["chart.js"]);
app.controller("LineCtrl", function ($scope) {
"use strict";
$scope.labels = ["0200", "0400", "0600", "0800", "1000", "1200", "1400",
"1600", "1800", "2000", "2200", "0000"];
$scope.series = ['Temperature (°C)'];
$scope.data = [
[26.5, 26.8, 26.3, 25.8, 29.4, 30.2, 31.5, 31.0, 28.4, 27.6, 26.3, 25.7]
];
$scope.onClick = function (points, evt) {
console.log(points, evt);
};
});
I have tried putting the chart function from main,js into data_controller.js and wrote $scope.data.push([mydata.data.substring(6,9)]) but that did nothing.
How do I call the function in data_controller.js and use the array in my $scope.data = [] in main.js?
If you want to reuse that method for retrieving data, it would be best to decouple it into a service. Then, you can use it all of your controllers.
Please note that code below is just to showcase the implementation, it might not work straight away if you just copy-paste it.
//statisticsSvc.js
angular.module('statisticsApp').service('statisticsService',['$http' function($http){
var data = [];
return {
getStatistics: function(){
return $http({
method : "POST",
url : "GatewayAPI.php",
})
.then(function(response){
var mydata,myJSON,myresult,myjava, myobj;
var i;
var Result;
var chartResultTemp = [];
var chartResultph = [];
var chartResultHum = [];
var resultType = [];
for(i=0; i<72;i++)
{
//storing data
mydata = response.data.data[i];
//retrieving data
myobj = mydata.data.substring(3,4);
resultType = mydata.data.substring(3, 4);
if(resultType === "A") {
chartResultTemp.push([mydata.data.substring(6,9)]);
} else if (resultType ==="B") {
chartResultph.push([mydata.data.substring(6, 9)]);
} else {
chartResultHum.push([mydata.data.substring(6, 9)]);
};
return {
records: response.data.data,
Result: Result,
chartResultTemp: chartResultTemp,
resultType: resultType,
chartResultph: chartResultph,
chartResultHum: chartResultHum
};
}
})
.catch(function(error){
console.log(error);
return error;
})
},
setData: function(a){ data = a;},
getData: function(){ return data;}
};
}]);
Then, you can use this service in your controllers:
//myCtrl
var app = angular.module('statisticsApp', [chart.js]).controller('myCtrl',
function ($scope, $http,statisticsService) {
//your call to service
statisticsService.getStatistics().then(function(response){
$scope.records = response.records;
$scope.test = response.Result;
$scope.test2 = response.chartResultTemp;
$scope.test3 = response. resultType;
}).error(function(error){
console.log(error);
});
//get data
$scope.data = statisticsService.getData();
});
//LineCtrl
var app = angular.module("statisticsApp", ["chart.js"]);
app.controller("LineCtrl", function ($scope, statisticsService) {
"use strict";
$scope.labels = ["0200", "0400", "0600", "0800", "1000", "1200", "1400",
"1600", "1800", "2000", "2200", "0000"];
$scope.series = ['Temperature (°C)'];
$scope.data = [
[26.5, 26.8, 26.3, 25.8, 29.4, 30.2, 31.5, 31.0, 28.4, 27.6, 26.3, 25.7]
];
//set data
statisticsService.setData($scope.data);
$scope.onClick = function (points, evt) {
console.log(points, evt);
};
});

Knockout, how to subscribe to every change in observableArray

can you help me to get subscription on every change of my observable collection and on every item change. Didn't find information on http://knockoutjs.com/documentation/observableArrays.html
$(document).ready(function () {
var Item = function (isSelected, isEnabled, errorState,
name, group, processed, errors, state) {
var self = this;
self._isSelected = ko.observable(isSelected);
self._isEnabled = ko.observable(isEnabled);
self._errorState = ko.observable(errorState);
self._name = ko.observable(name);
self._group = ko.observable(group);
self._processed = ko.observable(processed);
self._errors = ko.observable(errors);
self._state = ko.observable(state);
};
function ViewModel() {
var self = this;
self.SentinelList= ko.observableArray([
ko.observable(new Item(false, false, false, 'Mail1', 'Mailing', 4, 0, 1)),
ko.observable(new Item(false, false, false, 'Ident1', 'Identity', 5, 0, 0)),
ko.observable(new Item(false, false, false, 'Cook', 'Look', 2, 0, 1))]);
}
var vm = new ViewModel();
for (var item in vm.SentinelList) {
item.subscribe(function () {
console.log('List changed');
});
}
ko.applyBindings(vm);
});
You can use the subscribe againt the array :
self.SentinelList.subscribe(function (changes) {
changes.forEach(function (change) {
if (change.status === 'added') {
console.log('new item !!');
change.value.subcriptions.push(change.value.subscribe(event));
} else if (change.status === 'deleted') {
ko.utils.arrayForEach(change.value.subcriptions, function(s) {
if(s) s.dispose();
}
);
console.log('deleted item !!');
}
});
}, null, "arrayChange");
See fiddle
You can use external plugin that tracks changes of view model. For example KO-Reactor
https://github.com/ZiadJ/knockoutjs-reactor
in this case subscription will look like
for(var i = 0; i < vm.SentinelList().length; i++){
ko.watch(vm.SentinelList()[i], { recurse: true }, function(params, modifiedProperty) {
console.log('SentinelList changed');
});
}
JSFIDDLE

Mustache and nested templates

I have a tree-like setup, where each node contains its own Mustache template that might be wrapped in a parent node's template.
var templates = {
secondTmpl: Mustache.compile("<i>Yet another template.. Here's some text: {{text}}</i> {{date}}"),
template: Mustache.compile("<b>{{val}}</b><p>{{{outlet}}}</p><ul>{{#list}}<li>{{.}} </li>{{/list}}</ul> {{test}}")
};
var tree = [
{
template: "template",
data: { val: "yup!!", list: [1,2,3,4,5], test: function() { return new Date(); } },
children: [
{
view: "Main",
template: "secondTmpl",
data: { text: "Some Value", date: function() { return new Date(); } }
}
]
}
];
function MainView(options) {
this.template = options.template;
this.data = options.data;
this.childViews = options.childViews;
this.el = document.createElement("div");
}
MainView.prototype.render = function() {
View.prototype.render.call(this);
this.postRender();
return this;
};
MainView.prototype.postRender = function() {
this.el.getElementsByTagName("i")[0].style.border = "1px dotted red";
};
function View(options) {
this.template = options.template;
this.data = options.data;
this.childViews = options.childViews;
this.el = document.createElement("div");
}
View.prototype.render = function(renderChildren) {
if(this.childViews) {
this.data.outlet = "<div class=\"outlet\"></div>";
}
this.el.innerHTML = this.template(this.data);
if(this.childViews) {
this.childViews.forEach(function(view) {
this.el.getElementsByClassName("outlet")[0].appendChild(view.render().el);
}, this);
}
return this;
};
function traverse(node) {
var viewOptions = {
template: templates[node.template],
data: node.data
};
if(node.children) {
viewOptions.childViews = node.children.map(function(n) {
return traverse(n);
});
}
return node.view ? new window[node.view + "View"](viewOptions) : new View(viewOptions);
}
function init() {
tree.forEach(function(node) {
var view = traverse(node);
document.body.appendChild(view.render().el);
});
}
window.onload = init;​
Example here: http://jsfiddle.net/b4fTB/
The reason that I have the data in a tree is because the nested templates varies depending on the users data, and because many templates may be wrapped in different templates.
I don't know if what I'm doing here is stupid, but it allows me to render the templates from C# as well, which is quite nice.
So - the question (comments to the above is of course welcome). When dealing with a template with nested templates, it would be nice to have a simple function that only returns dom elements related to the actual template - and not dom elements from the nested templates. Is this even possible? And is it possible in a way that allows for deeply nested templates and not lose a great deal of performance? In other words, I have two templates where one of them is nested within the other in the jsfiddle. It would be nice not having to worry about nested views in the parent view when dealing with the dom.
Alright, I think I've found a way myself.
Following code requires mustachejs and composejs:
var noop = function() {};
var templates = {
secondTmpl: Mustache.compile("<i>Yet another template.. {{{outlet}}}Here's some text: {{text}}</i> {{date}}"),
template: Mustache.compile("<b>{{val}}</b><p>{{{outlet}}}</p><ul>{{#list}}<li>{{.}}</li>{{/list}}</ul> {{test}}")
};
var tree = [
{
view: "Main",
template: "template",
data: { val: "yup!!", list: [1, 2, 3, "Four", 5], test: function() { return new Date(); } },
children: [
{
template: "secondTmpl",
data: { text: "Some Value", date: function() { return new Date(); } }
},
{
view: "Test",
template: "secondTmpl",
data: { text: "ANOTHER TEMPLATE", date: function() { return new Date(); } },
children: [
{
template: "template",
data: { val: "Pretty nested template", list: [56, 52, 233, "afsdf", 785], test: "no datetime here" }
}
]
}
]
}
];
var View = Compose(function(options) {
Compose.call(this, options);
this.el = document.createElement(this.tag);
}, {
tag: "div",
render: function() {
if(this.childViews) {
this.data.outlet = "<div class=\"outlet\"></div>";
}
this.el.innerHTML = this.template(this.data);
this.didRender();
if(this.childViews) {
var lastEl;
this.childViews.forEach(function(view) {
if(!lastEl) {
var outlet = this.el.getElementsByClassName("outlet")[0];
lastEl = view.render().el;
outlet.parentNode.replaceChild(lastEl, outlet);
} else {
var el = view.render().el;
lastEl.parentNode.insertBefore(el, lastEl.nextSibling);
lastEl = el;
}
}, this);
}
this.didRenderDescendants();
return this;
},
didRender: noop,
didRenderDescendants: noop
});
var TestView = View.extend({
didRender: function() {
var nodes = this.el.querySelectorAll("*");
for(var i = 0; i < nodes.length;i++)
nodes[i].style.border = "2px dotted red";
}
});
var MainView = View.extend({
didRender: function() {
var nodes = this.el.querySelectorAll("*");
for(var i = 0; i < nodes.length;i++)
nodes[i].style.backgroundColor = "lightgray";
}
});
function traverse(node) {
var viewOptions = {
template: templates[node.template],
data: node.data
};
if(node.children) {
viewOptions.childViews = node.children.map(function(n) {
return traverse(n);
});
}
return node.view ? new window[node.view + "View"](viewOptions) : new View(viewOptions);
}
function init() {
tree.forEach(function(node) {
var view = traverse(node);
window["view"] = view;
document.body.appendChild(view.render().el);
});
}
window.onload = init;
The trick is to replace the div.outlet with the first child view instead of appending to it. Then it's a matter of inserting the other child views next to each other.

Categories