I have a backbone.js model similar to the one shown below.
Filters = Backbone.Model.extend({
defaults : {
title: [ ["title1", "easy"], ["title2", "hard"] ]
}
});
I'm trying to add an element to the first-level array, such that the model then becomes:
Filters = Backbone.Model.extend({
defaults : {
title: [ ["title1", "easy"], ["title2", "hard"], ["title3", "medium"] ]
}
});
The code I have right now is this:
function setFilters() {
var options = {};
for (var facet in facets) {
for (var facetKey in facets[facet]) {
if (!filterExists(facetKey)) {
options[facetKey] = new Array(new Array(facets[facet][facetKey], "equals"));
}
else {
(filters[facetKey]).push(new Array(facets[facet][facetKey], "equals"));
}
}
}
filters.set(options);
}
The function filterExists simply checks if the key "title" is present in the model. When I run this, it says that filters[facetKey] is undefined. But isn't this the first-level array I need to push my element into?
You can access model attributes with .get() and .set() functions, or directly via the .attributes property:
http://documentcloud.github.com/backbone/#Model-attributes
var filters = new Filters();
filters.attributes.facetKey.push( [...] );
OR
filters.set('facetKey', ( filters.get('facetKey') || []).concat([...]));
Anyway, here is your transformed function which may or may not work:
function setFilters() {
for (var facet in facets) {
for (var facetKey in facets[facet]) {
var f = [ facets[facet][facetKey], "equals" ];
if( filterExists(facetKey)) {
// OR: if( filters.attributes[ facetKey ]){
filters.attributes[ facetKey ].push( f );
}else{
filters.attributes[ facetKey ] = [ f ];
}
}
}
// trigger change event for all attributes
filters.set( filters.attributes );
}
Bonus:
(filters.attributes[ facetKey ] = filters.attributes[ facetKey ] || [] ).push(f);
Related
I am trying to link a json object to multiple objects.
$scope.persons = [
{"prename":"Max", "surname":"Shepherd"},
{"prename":"Sarah", "surname":"Shepherd"}
];
$scope.contracts = [
{"contract":"liability", "payment":"8.40"},
{"contract":"health", "payment":"48.12"}
];
// Save new Person
$scope.newPerson = {};
$scope.savePerson = function() {
$scope.persons.push($scope.newPerson);
$scope.newPerson = {};
}
// Save new Contract
$scope.newContract = {};
$scope.saveContract = function() {
$scope.contract.push($scope.newContract);
$scope.newContract = {};
}
How can I save a new Contract and link/nest it to 2 persons.
e.g. the liability contract should be nested to 2 persons.
The health contract should be nested only to 1 person.
But the contract should also be an own object.
The final array should propably look like this:
$scope.persons = [
{
"prename":"Max",
"surname":"Shepherd",
"contracts": {
{"contract":"liability", "payment":"8.40"}
}
},
{
"prename":"Sarah",
"surname":"Shepherd",
"contracts": {
"contract":"liability", "payment":"8.40"
"contract":"health", "payment":"48.12"
}
}
];
$scope.contracts = [
{"contract":"liability", "payment":"8.40"},
{"contract":"health", "payment":"48.12"}
];
you could add a contract id, and then link the id to each person who has the contract.
{"contract":"liability", "payment":"8.40","contractKey":"123"},
{"contract":"health", "payment":"48.12","contractKey":"321"}
$scope.persons = [
{
"prename":"Max",
"surname":"Shepherd",
"contracts": {
"123",
"321"
}
},
{
"prename":"Sarah",
"surname":"Shepherd",
"contracts": {
"123"
}
}
];
Then you would need a function to search for the correct contracts
function findContractForAllPeople(){
angular.forEach($persons,function(key,values){
angular.forEach(values,function(DataKey,val){
angular.forEach($contracts,function(contractKey,contractDetails)
if(DataKey === "contracts"){
if($scope.contracts.contractKey === val){
$scope.finalArray[prename] = {"contracts":contractDetails }
}
})
})
})
}
this will create an object that will look like this
{
Max:{
"contracts":{"contract":"liability", "payment":"8.40","contractKey":"123"},
{"contract":"health", "payment":"48.12","contractKey":"321"}}
},
Sarah:{
{"contract":"liability", "payment":"8.40","contractKey":"123"}
}
I'm trying to print all created groups and they're children so it'll look like that:
[ [ 'Father1', 'Child1', 'Child2', 'Child3' ],
[ 'Father1', 'Child1', 'Child4' ],
[ 'Father1', 'Child1', 'Child5' ] ]
The problems I encountered are varied. from:
var keys = name.keys(o); ^ TypeError: name.keys is not a function to total stack overflow, iv'e debugged the printPath function and it's doing it's job separately but not with my final tree structure.
My tree and print function looks like that:
groups.js:
class groups {
constructor() {
this.root = new Group('root');
}
printPath(name){
this.root.getPath(name)
}
group.js:
class Group {
constructor(name, parent) {
this.name = name;
this.parent = parent || null;
this.children = [];
this.users = new users || null;
}
getPath(name) {
function iter(o, p) {
var keys = name.keys(o);
if (keys.length) {
return keys.forEach(function (k) {
iter(o[k], p.concat(k));
});
}
result.push(p);
}
var result = [];
iter(name, []);
return result;
}
Edit:
For creating a group i'm using a menu handler function:
function createGroup(callback) {
rl.question('Add name for father group: \n', (parent) => {
let parentGroup = programdata.groups.findGroupByName(parent);
if (!parentGroup) {
parentGroup = programdata.groups.root;
}
rl.question('name of new group\n', (groupName) => {
parentGroup.setChildren(new Group(groupName, parentGroup));
console.log(parentGroup);
callback();
});
})
}
findGroupByNameis a nice recursion i made that finds nested groups (feel free to use!) sitting in class groups.
findGroupByName(name) {
if (!name) return null;
return this._findGroupByNameInternal(this.root, name);
}
_findGroupByNameInternal(group, name) {
if (!group) return null;
if (group.name === name) return group;
for (const g of group.children) {
const result = this._findGroupByNameInternal(g, name);
if (!result) continue;
return result;
}
}
And setChildren function placed in class Group:
setChildren(child) {
this.children.push(child);
}
EDIT:
Thank you for the answer, could you please help me realize your method in my menu handler? iv'e tried this: and it giving me nothing.
function createGroup(callback) {
rl.question('Add name for father group: \n', (parent) => {
let parentGroup = programdata.groups.findGroupByName(parent);
let treePath = Group.root.printPath();
if (!parentGroup) {
parentGroup = programdata.groups.root;
}
rl.question('name of new group\n', (groupName) => {
parentGroup.addChild(new Group(groupName, parentGroup));
console.log(treePath);
callback();
});
})
}
The root cause you got the error TypeError: name.keys is not a function is that a string is passed into getPath(name) as argument name, you know the JS string object doesn't have a function property keys.
I refactor your code and fix some error, here is the testable version. Pls put them into the same folder and run test.js.
group.js
class Group {
constructor(name, parent) {
this.name = name;
this.parent = parent || null; // Point to this group's father
this.children = []; // Children of this group, can be sub-group or string
if (!!parent) { // Link to the father
parent.addChild(this);
}
// this.users = new users || null; // Useless, remove it.
}
addChild(...args) {
for(let o in args) {
this.children.push(args[o]);
}
}
/**
* Recursion to build the tree
* #param group
* #returns {*}
*/
iter(group) {
let children = group.children;
if (Array.isArray(children)) { // If the child is a group
if (children.length > 0) {
let result = [];
result.push(group.name);
for (let child of children) {
result.push(group.iter(child));
}
return result;
}
else {
return [];
}
}
else { // If the group is a string
return group;
}
}
getPath() {
return this.iter(this);
}
}
module.exports = Group;
groups.js
let Group = require('./group');
class Groups {
constructor() {
this.root = new Group('root');
}
printPath() {
return this.root.getPath();
}
}
module.exports = Groups;
test.js
let Group = require('./group');
let Groups = require('./groups');
// Root
let rootGroups = new Groups();
// Group 1
let group1 = new Group('Father1', rootGroups.root);
group1.addChild('Child1', 'Child2', 'Child3');
// Group 2
let group2 = new Group('Father1', rootGroups.root);
group2.addChild('Child1', 'Child4');
// Group 3
let group3 = new Group('Father1', rootGroups.root);
group3.addChild('Child1', 'Child5');
let treePath = rootGroups.printPath();
console.log(treePath);
The output is:
[ 'root',
[ 'Father1', 'Child1', 'Child2', 'Child3' ],
[ 'Father1', 'Child1', 'Child4' ],
[ 'Father1', 'Child1', 'Child5' ] ]
Process finished with exit code 0
Enjoy it :)
Ok, found a solution.
Treeshow(){
var node = this.root;
var depth = '-'
recurse( node );
function recurse( node) {
depth +='-'
console.log(depth+node.name);
for (var child in node.children ) {
recurse(node.children[child]);
}
depth = depth.slice(0, -1);
}
}
that will show my tree just like that:
--root
---FooFather
----BarSemiFather
-----FooChild
------BarBaby
I am not very good with my javascript but recently needed to work with a library to output an aggregated table. Was using fin-hypergrid.
There was a part where I need to insert a sum function (rollups.sum(11) in this example)to an object so that it can compute an aggregated value in a table like so:
aggregates = {Value: rollups.sum(11)}
I would like to change this value to return 2 decimal places and tried:
rollups.sum(11).toFixed(2)
However, it gives the error : "rollups.sum(...).toFixed is not a function"
If I try something like:
parseFloat(rollups.sum(11)).toFixed(2)
it throws the error: "can't assign to properties of (new String("NaN")): not an object"
so it has to be a function object.
May I know if there is a way to alter the function rollups.sum(11) to return a function object with 2 decimal places?
(side info: rollups.sum(11) comes from a module which gives:
sum: function(columnIndex) {
return sum.bind(this, columnIndex);
}
)
Sorry I could not post sample output here due to data confidentiality issues.
However, here is the code from the example I follow. I basically need to change rollups.whatever to give decimal places. The "11" in sum(11) here refers to a "column index".
window.onload = function() {
var Hypergrid = fin.Hypergrid;
var drillDown = Hypergrid.drillDown;
var TreeView = Hypergrid.TreeView;
var GroupView = Hypergrid.GroupView;
var AggView = Hypergrid.AggregationsView;
// List of properties to show as checkboxes in this demo's "dashboard"
var toggleProps = [{
label: 'Grouping',
ctrls: [
{ name: 'treeview', checked: false, setter: toggleTreeview },
{ name: 'aggregates', checked: false, setter: toggleAggregates },
{ name: 'grouping', checked: false, setter: toggleGrouping}
]
}
];
function derivedPeopleSchema(columns) {
// create a hierarchical schema organized by alias
var factory = new Hypergrid.ColumnSchemaFactory(columns);
factory.organize(/^(one|two|three|four|five|six|seven|eight)/i, { key: 'alias' });
var columnSchema = factory.lookup('last_name');
if (columnSchema) {
columnSchema.defaultOp = 'IN';
}
//factory.lookup('birthState').opMenu = ['>', '<'];
return factory.schema;
}
var customSchema = [
{ name: 'last_name', type: 'number', opMenu: ['=', '<', '>'], opMustBeInMenu: true },
{ name: 'total_number_of_pets_owned', type: 'number' },
{ name: 'height', type: 'number' },
'birthDate',
'birthState',
'employed',
{ name: 'income', type: 'number' },
{ name: 'travel', type: 'number' }
];
var peopleSchema = customSchema; // or try setting to derivedPeopleSchema
var gridOptions = {
data: people1,
schema: peopleSchema,
margin: { bottom: '17px' }
},
grid = window.g = new Hypergrid('div#json-example', gridOptions),
behavior = window.b = grid.behavior,
dataModel = window.m = behavior.dataModel,
idx = behavior.columnEnum;
console.log('Fields:'); console.dir(behavior.dataModel.getFields());
console.log('Headers:'); console.dir(behavior.dataModel.getHeaders());
console.log('Indexes:'); console.dir(idx);
var treeView, dataset;
function setData(data, options) {
options = options || {};
if (data === people1 || data === people2) {
options.schema = peopleSchema;
}
dataset = data;
behavior.setData(data, options);
idx = behavior.columnEnum;
}
// Preset a default dialog options object. Used by call to toggleDialog('ColumnPicker') from features/ColumnPicker.js and by toggleDialog() defined herein.
grid.setDialogOptions({
//container: document.getElementById('dialog-container'),
settings: false
});
// add a column filter subexpression containing a single condition purely for demo purposes
if (false) { // eslint-disable-line no-constant-condition
grid.getGlobalFilter().columnFilters.add({
children: [{
column: 'total_number_of_pets_owned',
operator: '=',
operand: '3'
}],
type: 'columnFilter'
});
}
window.vent = false;
//functions for showing the grouping/rollup capabilities
var rollups = window.fin.Hypergrid.analytics.util.aggregations,
aggregates = {
totalPets: rollups.sum(2),
averagePets: rollups.avg(2),
maxPets: rollups.max(2),
minPets: rollups.min(2),
firstPet: rollups.first(2),
lastPet: rollups.last(2),
stdDevPets: rollups.stddev(2)
},
groups = [idx.BIRTH_STATE, idx.LAST_NAME, idx.FIRST_NAME];
var aggView, aggViewOn = false, doAggregates = false;
function toggleAggregates() {
if (!aggView){
aggView = new AggView(grid, {});
aggView.setPipeline({ includeSorter: true, includeFilter: true });
}
if (this.checked) {
grid.setAggregateGroups(aggregates, groups);
aggViewOn = true;
} else {
grid.setAggregateGroups([], []);
aggViewOn = false;
}
}
function toggleTreeview() {
if (this.checked) {
treeView = new TreeView(grid, { treeColumn: 'State' });
treeView.setPipeline({ includeSorter: true, includeFilter: true });
treeView.setRelation(true, true);
} else {
treeView.setRelation(false);
treeView = undefined;
delete dataModel.pipeline; // restore original (shared) pipeline
behavior.setData(); // reset with original pipeline
}
}
var groupView, groupViewOn = false;
function toggleGrouping(){
if (!groupView){
groupView = new GroupView(grid, {});
groupView.setPipeline({ includeSorter: true, includeFilter: true });
}
if (this.checked){
grid.setGroups(groups);
groupViewOn = true;
} else {
grid.setGroups([]);
groupViewOn = false;
}
}
you may try:
(rollups.sum(11)).toFixed(2)
enclosing number in parentheses seems to make browser bypass the limit that identifier cannot start immediately after numeric literal
edited #2:
//all formatting and rendering per cell can be overridden in here
dataModel.getCell = function(config, rendererName) {
if(aggViewOn)
{
if(config.columnName == "total_pets")
{
if(typeof(config.value) == 'number')
{
config.value = config.value.toFixed(2);
}
else if(config.value && config.value.length == 3 && typeof(config.value[1]) == 'number')
{
config.value = config.value[1].toFixed(2);
}
}
}
return grid.cellRenderers.get(rendererName);
};
var aclData=[
{
'Manage Users':
['add','view','edit','delete']
},
{
'Manage Role':
['add','view','edit']
}
];
How to check 'view' exist in 'Manage Role'
This should do the trick:
for (var i = 0; i<aclData["Manage Users"].length; i++){
if(aclData["Manage Users"][i] == "view"){
// exists
}
}
Edit: Assumend you hava a dictonary. E.G:
var dict = []; // create an empty array
var dict = [];
aclData.push({
key: "Manage Users",
value: ...
});
Consider this as my json data.
I want to filter the "gridValues" in the data using value "LAN". I have used Ext js filter method. It doesn't return the filter data.
var tableData = [
{
"TABLE_TITLE": "Details",
"tableColumns": {
"COLUMNNAME_0": "Interface",
"COLUMNNAME_1": "Conversation",
"COLUMNNAME_2": "Data Flow(KB)"
},
"gridValues": [
{
"COLUMVal_0": "LAN",
"COLUMVal_1": "192.168.9.113 to 61.16.173.233",
"COLUMVal_2": "1132.7"
},
{
"COLUMVal_0": "TATA",
"COLUMVal_1": "192.168.8.67 to 111.221.115.98",
"COLUMVal_2": "619.72"
},
{
"COLUMVal_0": "CITI",
"COLUMVal_1": "192.168.8.60 to 23.6.112.201",
"COLUMVal_2": "619.2"
}
]
}
];
I used the following code for filtering data:
var arry =[];
var fliterarry =[];
var i,u;
for (i=0;i<tableData.length;i++) {
arry.push(tableData[i].gridValues);
}
var arryFtr = arry.filter(function(e){
for (u=0;u<e.length;u++) {
if(e[u].COLUMVal_0 === 'TATA'){
tableData[u].gridValues.push(e[u]);
}
return e[u].COLUMVal_0 == 'TATA';
}
return fliterarry
});
I guess you want to filter data with COLUMVal_0 equals "TATA" , right ?
Try following codes in your function :
var filterArray = [];
for ( tdKey in tableData ) {
for ( gvKey in tableData[tdKey].gridValues ) {
if ( tableData[tdKey].gridValues[gvKey].COLUMVal_0 == "TATA" ) {
filterArray.push(tableData[tdKey].gridValues[gvKey]);
}
}
}
return fliterarry;