Inline array store data in ExtJS4? - store

I'm unable to load inline array data into a store. In particular, this fails.
Can someone explain why? I even tried adding a memory proxy with an array reader and still no dice.
Ext.define('MyApp.store.ComboboxState', {
extend: 'Ext.data.Store',
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
storeId: 'ComboboxState',
data: [
[
'AL',
'Alabama'
]
]
,fields: [
{
name: 'state'
},
{
name: 'name'
}
]
}, cfg)]);
}
});
Still doesn't work with this memory proxy/array reader:
proxy: {
type: 'memory',
reader: {
type: 'array'
}
}

Just extend from ArrayStore, like this:
Ext.define('MyApp.store.ComboboxState', {
extend: 'Ext.data.ArrayStore',
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
storeId: 'ComboboxState',
data: [
[
'AL',
'Alabama'
]
]
,fields: ['state', 'name' ]
}, cfg)]);
}
});
JsFiddle to try: http://jsfiddle.net/voidmain/hKwbJ/

Related

How to restructure an array base on an value inside the original array in node js

I am trying to restructure an array. Instead of variant_id at the top, i would like to make collection_id to the top. if the collection_id is the same they should be in the same array. I try using foreach but seems didn't work.
[
{
variant_id: '39264031277264',
collection: [
{
collection_id: '260687954128',
value: true
}
]
},
{
variant_id: '39264022134992',
collection: [
{
collection_id: '260687954128',
value: true
}
]
},
{
variant_id: '40460795642064',
collection: [
{
collection_id: '277033681104',
value: true
}
]
}
]
This is the expected result
[
{
"collection_id":"260687954128",
"variant_id":[
"39264031277264",
"39264022134992"
]
},
{
"collection_id":"277033681104",
"variant_id":[
"40460795642064"
]
}
]
You can define a simple mapping function that collects all collection_ids and keeps track of the respective variant_ids:
const data = [{
variant_id: '39264031277264',
collection: [{collection_id: '260687954128', value: true}]
}, {
variant_id: '39264022134992',
collection: [{collection_id: '260687954128', value: true}]
}, {variant_id: '40460795642064', collection: [{collection_id: '277033681104', value: true}]}
];
function mapData(input) {
const collections = {};
for (const variant of input) {
for (const collection of variant.collection) {
collections[collection.collection_id] = collections[collection.collection_id] ?? [];
collections[collection.collection_id].push(variant.variant_id);
}
}
return Object
.entries(collections)
.map(([key, value]) => ({collection_id: key, variant_id: value}));
}
console.log(mapData(data));
The below solution may be one possible way to achieve the desired objective.
It uses the following JavaScript concepts/features/ideas:
Object.values
Array.reduce()
De-structuring
... spread operator
?. optional chaining operator
?? nullish coalescing operator
Implicit return
Code Snippet
const reGroupUsingCollectionId = arr => (
Object.values( // extract only the 'values' of resulting object
arr.reduce( // use .reduce() to iterate the array
(acc, itm) => ( // 'acc' is the accumulator & 'itm' is current element
itm.collection.reduce( // use .reduce() to iterate over 'collection' array
(fin, {collection_id}) => ({ // 'fin' is the inner-reduce's accumulator
...fin, // collection_id is de-structured from iterator
[collection_id]: {
collection_id,
variant_id: [ // populate the variant_id array
...( //
fin[collection_id] // use existing variant_id array if collection_id
?.variant_id // already added to accumulator (fin)
?? [] // nullish coalescing as empty
),
itm.variant_id // append itm.variant_id to variant_id array
]
}
}),
{...acc} // initialize 'fin' to be 'acc'
)
),
{} // initialize 'acc' to be empty object
)
)
);
const data = [{
variant_id: '39264031277264',
collection: [{
collection_id: '260687954128',
value: true
}]
}, {
variant_id: '39264022134992',
collection: [{
collection_id: '260687954128',
value: true
}]
}, {
variant_id: '40460795642064',
collection: [{
collection_id: '277033681104',
value: true
}]
}
];
console.log(reGroupUsingCollectionId(data));
Explanation
Inline comments provide detailed description of each significant step.

Generate friendly JSON from XML in NodeJS

Currently, I'm receiving an API request that has the crazy structure to the data, I'm attempting to parse the XML part of the response to an array/JSON so I can handle it.
Here's the exact request I am receiving:
{
username: 'test',
apiaccesskey: 'aa7a8157-3c17-4b63-806f-7aeff42ae21f',
action: 'placeimeiorder',
requestformat: 'JSON',
parameters:
'<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n',
version: '7.2'
}
I've tried parsing using this library (xml2js) but it's generating a result like this:
let parseresult = await parser.parseStringPromise(req.body.parameters);
console.log(parseresult);
{ PARAMETERS:
{ CUSTOMFIELD: [ 'bnVsbA==' ],
ID: [ '1' ],
SERVICEID: [ '1' ],
IMEI: [ '12345678910' ],
QNT: [ '1' ],
SERVER: [ '0' ],
MODELID: [ '' ],
PROVIDERID: [ '' ],
NETWORK: [ '' ],
PIN: [ '' ],
KBH: [ '' ],
MEP: [ '' ],
PRD: [ '' ],
TYPE: [ '' ],
LOCKS: [ '' ],
REFERENCE: [ '' ],
SN: [ '' ],
SECRO: [ '' ] } }
which is far from ideal when trying to handle, how could I change it so I could simply access individual key/values like parseresult.IMEI or parseresult.CUSTOMFIELD
Should just be a setting.
Code:
const xml2js = require('xml2js');
const parser = new xml2js.Parser({ explicitArray: false });
const xml = "<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n";
parser.parseString(xml, (err, result) => {
console.dir(result);
});
Reference: https://github.com/Leonidas-from-XIV/node-xml2js#options
Output:
{
PARAMETERS: {
CUSTOMFIELD: 'bnVsbA==',
ID: '1',
SERVICEID: '1',
IMEI: '12345678910',
QNT: '1',
SERVER: '0',
MODELID: '',
PROVIDERID: '',
NETWORK: '',
PIN: '',
KBH: '',
MEP: '',
PRD: '',
TYPE: '',
LOCKS: '',
REFERENCE: '',
SN: '',
SECRO: ''
}
}
Alternative:
Using the async/await like you have above:
const xml2js = require('xml2js');
(async () => {
const parser = new xml2js.Parser({ explicitArray: false });
const xml = "<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n";
try {
console.log(await parser.parseStringPromise(xml))
} catch (error) {
console.log('ERROR', error);
}
})();
If you want complete control over the conversion, try saxon-js (released on Node.js a couple of weeks ago, available from npm).
For example you could do it in XPath 3.1 like this:
const SaxonJS = require("saxon-js");
SaxonJS.getResource({text:xml, type:"xml"})
.then(doc => {
SaxonJS.serialize(
SaxonJS.XPath.evaluate(
"map:merge(/PARAMETERS/* ! map{name(): string()})", doc),
{method:"json", indent:true}))});
You could extend this, for example to select which fields of the XML to include in the result.
Or for even more flexibility, you could do it in XSLT3.
(Not tested.)
you can also use camaro, a xpath-powered template to transform the value. it looks like this
const { transform } = require('camaro')
const data = {
username: 'test',
apiaccesskey: 'aa7a8157-3c17-4b63-806f-7aeff42ae21f',
action: 'placeimeiorder',
requestformat: 'JSON',
parameters:
'<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n',
version: '7.2',
}
async function main() {
console.log(await transform(data.parameters, {
customerField: 'PARAMETERS/CUSTOMFIELD',
customerId: 'PARAMETERS/ID',
serviceId: 'PARAMETERS/SERVICEID',
}));
}
main()
output
{ customerField: 'bnVsbA==', customerId: '1', serviceId: '1' }
If you want more fields, you can just edit the template

How to filter children in tree structure in Tabulator?

I tried callingsetFilter function on my Tabulator tree structure, in order to filter out items. It seems to only filter out top parents. Any idea how to make this work for any level (any children or parents)? http://tabulator.info/docs/4.1/tree doesn't say much about how filtering works.
Function
table.setFilter('id', '=', 214659) is not returning anything...
Tree structure
[
{
"level":0,
"name":"word1",
"id":125582,
"_children":[
{
"level":1,
"name":"word6",
"id":214659
},
{
"level":1,
"name":"word7",
"id":214633
},
{
"level":1,
"name":"word2",
"id":214263,
"_children":[
{
"level":2,
"name":"word8",
"id":131673
},
{
"level":2,
"name":"word9",
"id":125579
},
{
"level":2,
"name":"word10",
"id":125578
},
{
"level":2,
"name":"word4",
"id":172670,
"_children":[
{
"level":3,
"name":"word13",
"id":172669
},
{
"level":3,
"name":"word14",
"id":174777
},
{
"level":3,
"name":"word5",
"id":207661,
"_children":[
{
"level":4,
"name":"word15",
"id":216529
},
{
"level":4,
"name":"word16",
"id":223884,
"_children":[
{
"level":5,
"name":"word17",
"id":223885,
"_children":[
{
"level":6,
"name":"word18",
"id":229186,
"_children":[
{
"level":7,
"name":"word19",
"id":219062
},
{
"level":7,
"name":"word20",
"id":222243
}
]
}
]
}
]
}
]
}
]
},
{
"level":2,
"name":"word3",
"id":214266,
"_children":[
{
"level":3,
"name":"word11",
"id":216675
},
{
"level":3,
"name":"word12",
"id":216671
}
]
}
]
}
]
}
]
After a little searching found out an extension for lodash library called deepdash which has deep level filtering and it works quite well.
You will have 2 new dependencies but I think it will serve your purpose.
Check the documentation on how to install them here
In the snippet here you can see in the log the results. I made a sandbox also here
This is for a list of ids, one or more.
If you need only for one value change the conditional. return _.indexOf(idList, value.id) !== -1; to return id===value.id; where id is your id variable
Also after looking at the documentation from Tabulator, the have only one level filtering, even if you write your own custom filter it wouldn't help, because it expects a bool value to render the row or not. But only for the first level, so if the parent is not what you look for the child will be ignored. The only option for you is to filter the data outside the Tabulator.
const data = [
{
level: 0,
name: "word1",
id: 125582,
_children: [
{
level: 1,
name: "word6",
id: 214659
},
{
level: 1,
name: "word7",
id: 214633
},
{
level: 1,
name: "word2",
id: 214263,
_children: [
{
level: 2,
name: "word8",
id: 131673
},
{
level: 2,
name: "word9",
id: 125579
},
{
level: 2,
name: "word10",
id: 125578
},
{
level: 2,
name: "word4",
id: 172670,
_children: [
{
level: 3,
name: "word13",
id: 172669
},
{
level: 3,
name: "word14",
id: 174777
},
{
level: 3,
name: "word5",
id: 207661,
_children: [
{
level: 4,
name: "word15",
id: 216529
},
{
level: 4,
name: "word16",
id: 223884,
_children: [
{
level: 5,
name: "word17",
id: 223885,
_children: [
{
level: 6,
name: "word18",
id: 229186,
_children: [
{
level: 7,
name: "word19",
id: 219062
},
{
level: 7,
name: "word20",
id: 222243
}
]
}
]
}
]
}
]
}
]
},
{
level: 2,
name: "word3",
id: 214266,
_children: [
{
level: 3,
name: "word11",
id: 216675
},
{
level: 3,
name: "word12",
id: 216671
}
]
}
]
}
]
}
];
const idList = [214659];
const found = _.filterDeep(
data,
function(value) {
return _.indexOf(idList, value.id) !== -1;
},
{ tree: true, childrenPath: '_children' }
);
console.log(found);
<script src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/deepdash/browser/deepdash.min.js"></script>
<script>
deepdash(_);
</script>
Here is a recursive function that will find the parent and/or children matching a condition.
In this example, the parent item will always be displayed if a child item is a match - even if the parent itself is not a match - but you can easily adjust the code to your needs by tuning the test in the for loop.
var filterTree = function (data, filter) {
if (data['_children'] && data['_children'].length > 0) {
for (var i in data['_children']) {
return data[filter.field] == filter.value || filterTree(data['_children'][i], filter);
}
}
return data[filter.field] == filter.value;
};
Call this function as a custom filter callback:
table.setFilter(filterTree, {field:'myfield', type:'=', value:'myvalue'});
Note that this is just example code that focuses on the logic of filtering a tree recursively. The above works only for the '=' comparison.
In a real situation, you will have to implement more code to handle all other operators supported by tabulator, as dynamic operator assignment is not possible in Javascript. You could maybe consider eval() but that's another story.
More info about dynamic operator assignment here:
Are Variable Operators Possible?
Here is an example of implementation handling all tabulator operators:
// Operators
var compare = {
'=': function(a, b) { return a == b },
'<': function(a, b) { return a < b },
'<=': function(a, b) { return a <= b },
'>': function(a, b) { return a > b },
'>=': function(a, b) { return a >= b },
'!=': function(a, b) { return a != b },
'like': function(a, b) { return a.includes(b)}
};
// Filter function
var filterTree = function (data, filter) {
if (data['_children'] && data['_children'].length > 0) {
for (var i in data['_children']) {
return compare[filter.type](data[filter.field], filter.value) || filterTree(data['_children'][i], filter);
}
}
return compare[filter.type](data[filter.field], filter.value);
};
// Set a filter. The operator can now be provided dynamically
table.setFilter(filterTree, {field:'myfield', type: '>=', value:'myvalue'});

Create a JSON object using an array of nodes

I the results of a table that gives me the dynamic hierarchy of fields that i am needing to use to create a JSON object from.
EX:
[ [ 'request', 'cycleRange' ],
[ 'request', 'cycleRange', 'from' ],
[ 'request', 'cycleRange', 'to' ],
[ 'request', 'cycleRange', 'to', 'month' ],
[ 'request', 'cycleRange', 'to', 'year' ],
[ 'request', 'datestmt' ],
[ 'request', 'singleTran' ],
[ 'request', 'singleTran', 'datePost' ],
[ 'request', 'singleTran', 'dateTo' ] ]
The JSON object i am expecting to create with this sample should be:
let expected = {
request: {
cycleRange: {
from: null,
to: {
month: null,
year: null
}
},
datestmt: null,
singleTran: {
datePost: null,
dateTo: null
}
}
};
I am using this function to try and build the object, but i am only getting the final array as the object:
let final = {};
for (let i of heirarchy) {
assign(final, i, null);
}
function assign(obj, keyPath, value) {
let lastKeyIndex = keyPath.length - 1;
let key;
let i;
for (i=0; i<lastKeyIndex; i++) {
key = keyPath[i];
if (!(key in obj)) {
obj[key] = {};
} else {
if (i !== lastKeyIndex) {
obj[key] = {};
}
}
obj = obj[key];
}
obj[keyPath[lastKeyIndex]] = value;
}
Currently my results i am only getting: (the last index of my source hierarchy)
{"request":{"singleTran":{"dateTo":null}}}
Any help would be appreciated.
because obj is referencing final, this line is likely causing you mischief:
obj = obj[key];
This will overwrite the obj (in this case final) every iteration of hte loop. I would recommend keeping track of a separate variable so that final remains un-mutated
I have this solution but I think there is a lot of room for simplification and improvement, also I replaced null by {}.
You could use _.set from lodash: https://lodash.com/docs/4.17.11#set to replace set in my example.
const array = [ [ 'request', 'cycleRange' ],
[ 'request', 'cycleRange', 'from' ],
[ 'request', 'cycleRange', 'to' ],
[ 'request', 'cycleRange', 'to', 'month' ],
[ 'request', 'cycleRange', 'to', 'year' ],
[ 'request', 'datestmt' ],
[ 'request', 'singleTran' ],
[ 'request', 'singleTran', 'datePost' ],
[ 'request', 'singleTran', 'dateTo' ] ];
const set = (path, obj) => path.split('.').reduce((o,i)=> {
return o[i] ? o[i] : o[i] = {};
}, obj)
let myNewObject = {};
let path = '';
array.forEach(element => {
path = '';
element.forEach(key => {
path = path ? path + '.' + key : key;
set(path, myNewObject);
});
});
console.log(myNewObject);
I wound up using package deepmerge to merge the individual results into my final object
const deepmerge = require('deepmerge');
let final = {};
for (let i of heirarchy) {
let temp = {};
assign(temp, i, null);
final = deepmerge(final, temp);
}

Not Getting Search value in Sencha Touch using searchfield

I want to display predictive text in search field, value for predictive text which comes from server. Here is my code so far:
View:
Ext.define('MyApp.view.AutoSearch', {
extend: 'Ext.dataview.List',
alias : 'widget.mainPanel',
config: {
store : 'AutoSearchStore',
itemTpl: '<div class="myWord">'+
'<div>Word is --<b>{name}</b>--- after search!!!</div>' +
'</div>',
emptyText: '<div class="myWord">No Matching Words</div>',
items: [
{
xtype: 'toolbar',
docked: 'top',
items: [
{
xtype: 'searchfield',
placeHolder: 'Search...',
itemId: 'searchBox'
}
]
}
]
}
});
Store:
Ext.define('MyApp.store.AutoSearchStore',{
extend: 'Ext.data.Store',
config:
{
model: 'MyApp.model.AutoSearchModel',
autoLoad:true,
id:'Contacts',
proxy:
{
type: 'ajax',
url: 'http://alucio.com.np/trunk/dev/sillydic/admin/api/word/categories/SDSILLYTOKEN/650773253e7f157a93c53d47a866204dedc7c363',
reader:
{
rootProperty:''
}
}
}
});
Model:
Ext.define('MyApp.model.AutoSearchModel', {
extend: 'Ext.data.Model',
requires: ['MyApp.model.AutoSearchModelMenu'],
config: {
fields: [
{name:'data', mapping: 'data'},
{name: 'name'},
],
},
});
and
Ext.define('MyApp.model.AutoSearchModelMenu', {
extend: 'Ext.data.Model',
config: {
fields: [
'name',
],
belongsTo: "MyApp.model.AutoSearchModel"
}
});
Controller:
Ext.define('MyApp.controller.SearchAutoComplete', {
extend : 'Ext.app.Controller',
config: {
profile: Ext.os.deviceType.toLowerCase(),
stores : ['MyApp.store.AutoSearchStore'],
models : ['MyApp.model.AutoSearchModel'],
refs: {
myContainer: 'mainPanel'
},
control: {
'mainPanel': {
activate: 'onActivate'
},
'mainPanel searchfield[itemId=searchBox]' : {
clearicontap : 'onClearSearch',
keyup: 'onSearchKeyUp'
}
}
},
onActivate: function() {
console.log('Main container is active--Search');
},
onSearchKeyUp: function(searchField) {
queryString = searchField.getValue();
console.log(this,'Please search by: ' + queryString);
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
if(queryString){
var thisRegEx = new RegExp(queryString, "i");
store.filterBy(function(record) {
if (thisRegEx.test(record.get('name'))) {
return true;
};
return false;
});
}
},
onClearSearch: function() {
console.log('Clear icon is tapped');
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
},
init: function() {
console.log('Controller initialized for SearchAutoComplete');
}
});
Json Data Looks Like:
"data":[
{
"name":"paint",
"author":"admin",
"word_id":"1",
"category":"Business",
"is_favourite":"yesStar"
},
{
"name":"abacus",
"author":"admin",
"word_id":"2",
"category":"Education",
"is_favourite":"yesStar"
},
{
"name":"abate",
"author":"admin",
"word_id":"3",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"testing adsf",
"author":"admin",
"word_id":"7",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"sprite",
"author":"admin",
"word_id":"6",
"category":"Business",
"is_favourite":"noStar"
},
{
"name":"newword",
"author":"admin",
"word_id":"8",
"category":"Architecture",
"is_favourite":"noStar"
}
]
})
If I type "A", then it displays No Matching Words, but I have words from "A" on json coming from server. How to solve this problem?
Any idea!
Code Sources Link
I don't know why you are using two models but just one thing you need to specify in AutoSearchStore :
reader:
{
rootProperty:'data'
}
instead of
reader:
{
rootProperty:''
}
to get the expected results in the list.
Hope this will be helpful :)

Resources