Mobile list collapsible items - qooxdoo

I am trying to create a list of collapsible containers. The container should collapse and expand. I have created an example list item renderer.
qx.Class.define("mb.ui.list.QuotaWeekListRenderer",
{
extend : qx.ui.mobile.list.renderer.Default,
members :
{
__collapsible : null,
__weeksContainer : null,
_init : function()
{
this.ignoreBase;
this.__collapsible = this._createCollapsible();
this.add(this.__collapsible);
},
setTitle : function(title)
{
this.ignoreBase;
if (title && title.translate)
{
this.__collapsible.setTitle(title.translate());
}
else
{
this.__collapsible.setTitle(title);
}
},
addWeek : function(value)
{
var label = new qx.ui.mobile.basic.Label(value);
this.__collapsible.add(label);
},
_createCollapsible : function()
{
return new qx.ui.mobile.container.Collapsible();
},
// overridden
reset : function()
{
this.ignoreBase;
this.setTitle("");
this.__collapsible.getContent().removeAll();
}
}
});
var page = new qx.ui.mobile.page.NavigationPage();
page.setTitle("List");
page.addListener("initialize", function()
{
// List creation
var list = new qx.ui.mobile.list.List({
configureItem : function(item, data, row)
{
item.setTitle("Week " + parseInt(data.weekNo));
for (var i = 0, l = data.weekDates.length; i < l; i++)
{
item.addWeek(data.weekDates[i]);
}
},
createItemRenderer : function()
{
return new mb.ui.list.QuotaWeekListRenderer();
}
});
// Create the data
var data = [{title: "title1", weekNo: 1, weekDates : ["1/2/2014", "2/2/2014"]},
{title: "title2", weekNo : 2, weekDates : ["2/3/2015", "9/3/2015"]}];
list.setModel(new qx.data.Array(data));
page.getContent().add(list);
},this);
this.getManager().addDetail(page);
page.show();
The above can be run in Playground
My problem is that the items don't expand on 'tap'. Listener toggles the "collapsed" property of the container, but it has no effect on the DOM element. Any ideas how to fix it?

something like this, maybe?
Playground example

Related

Firebase Ionic Nested Search

I'm trying to make a search function.
When a user selects a product, a list of products should be shown belonging to some storage place.
For so far, I can only show the array Products with all the items in it. But when I want to go deeper and loop over each items (to search items that match with the selected item), I got an error:
Error: No index defined for Products
This is my code:
controllers.js:
.controller('InventoryCtrl', function($scope, Category, Inventory) {
$scope.categories = Category;
$scope.searchInventory = function(category){
var word = category.Category;
//console.log(word);
var ref = new Firebase('https://vivid-heat-2430.firebaseio.com/');
var invenRef = ref.child('Inventories');
var prodRef = invenRef.child('Products');
invenRef.orderByChild("Products").on("child_added", function(snapshot) {
var data = snapshot.val();
var store = data.Inventory;
var prod = data.Products;
console.log(prod);
snapshot.forEach(function(childSnapshot) {
var test = childSnapshot.val();
console.log(test);
//var key = childSnapshot.key();
//console.log(key);
});
});
};
})
I’ve already defined my index. But I still got this error.
I also tried it like this in my controller:
$scope.searchInventory = function(category){
var word = category.Category;
var ref = new Firebase('https://vivid-heat-2430.firebaseio.com/');
var invenRef = ref.child('Inventories');
var prodRef = invenRef.child('Products');
invenRef.orderByChild("Products").equalTo(word).on("child_added", function(snapshot){
console.log(snapshot.key());
});
};
})
Here I got no errors, But I can't log anything to see.
This is my firebase structure:
Database structure
Can you please point out what I did wrong? I'm still new to this and trying to learn from my mistakes.
Thanks in advance!
EDIT
My rules.json
{
"rules": {
".read": true,
".write": true,
"Inventories": {
".indexOn": "Products"
}
}
}
JSON file of db structure:
{
"Categorie" : {
"-K5a3iGlgi7PS0m3O4y8" : {
"Category" : "IQ 33cl BOX",
"Optional" : false,
"Size" : "24"
},
"-K5a3vNZRc2Cur9964Xs" : {
"Category" : "CL 33cl BOX",
"Optional" : true,
"Size" : "24"
},
"-K5a40Q79SCqWqMbqWQu" : {
"Category" : "IQ 33cl CASE",
"Optional" : true,
"Size" : "24"
},
"-K5a464FON4qdnqE9rgf" : {
"Category" : "CL 33cl CASE",
"Optional" : false,
"Size" : "24"
},
"-K5a4TAzHE8cRGPbNeij" : {
"Category" : "Empty CASES",
"Optional" : false,
"Size" : "24"
}
},
"Inventories" : {
"17-12-2015Storage 1" : {
"Date" : 1450366396979,
"Inventory" : "Storage 1",
"Products" : {
"CL 33cl BOX" : {
"boxes" : 0,
"full" : 11,
"half" : 13
},
"IQ 33cl BOX" : {
"boxes" : 0,
"full" : 60,
"half" : 0
}
}
},
"17-12-2015Storage Deb" : {
"Date" : 1450367128198,
"Inventory" : "Storage Deb",
"Products" : {
"IQ 33cl CASE" : {
"boxes" : 0,
"full" : 2,
"half" : 14
}
}
}
},
"Storages" : {
"-K5a4esu-1Na1hkKMP47" : { "name" : "Storage 1" },
"-K5a4ihb9L5z6qSqQxAx" : { "name" : "Storage Deb" },
"-K5a4l9odWuPUJJuN8OR" : { "name" : "Storage Bart" },
"-K5a4nsc47N3k_hMVl2h" : { "name" : "Storage Debosz" }
}
}
index.html
<div style="max-height: 300px" ng-controller="InventoryCtrl">
<ion-list>
<ion-radio ng-repeat="category in categories" class="item-accordion" ng-model="checked.check" value="{{category.Category}}" ng-click="searchInventory(category)">
<p>{{category.Category}}</p>
</ion-radio>
<br>
</ion-list>
</div>
Your structure (according to the link)
Inventories
some_node_name_1
Inventory: xxxx
Products:
product_name: "product a"
product_price: 30
some_node_name_2
Inventory: xxxx
Products:
product_name: "product b"
product_price: 50
and your query path
var ref = new Firebase('https://vivid-heat-2430.firebaseio.com/');
var invenRef = ref.child('Inventories');
var prodRef = invenRef.child('Products');
(note prodRef doesn't appear to be used)
So how about:
var ref = new Firebase('https://vivid-heat-2430.firebaseio.com/Inventories');
ref.orderByChild("Products/product_name").on("child_added", function(snapshot) {
});
And the .indexOn rule should be at the same level as where you do the query (product_name).
Edit with more info:
A nodes key is indexed automatically so you don't need to add .index for the node Products (it's already done). However, you would add a index for a child of Products for example:
{
"rules": {
"Inventories": {
"Products": {
".indexOn": ["product_name"]
}
}
}
}
or (I believe this is another option)
{
"rules": {
"Inventories": {
".indexOn": ["Products/product_name"]
}
}
}
I've solved the problem by using Object.keys() to get the name of the products.
I also used a for loop to search for the matching product.
My controller looks like this now:
.controller('InventoryCtrl', function($scope, $firebaseObject, Category, Inventory) {
$scope.categories = Category;
$scope.searchInventory = function(category){
var word = category.Category;
var ref = new Firebase('https://vivid-heat-2430.firebaseio.com/');
var invenRef = ref.child('Inventories');
var prodRef = invenRef.child('Products');
var test22 = [];
invenRef.orderByChild("Products").on("child_added", function(snapshot) {
var data = snapshot.val();
var store = data.Inventory;
var test = Object.keys(prod);
for( var i = 0; i < test.length; i++){
if (test[i] == word) {
test22.push(data.Inventory);
};
};
$scope.show = test22;
});
};
})

Angular.js count item iterations when filtering objects with ng-options

working on a list filtering with Angular, where listing the items based on region and creating an option select to list these regionsm where I have to remove duplications, and will need a count number next to the region name, which represents how many items from the same region.
I found this thread : How to count unique results based on a particular properties within ng-options but its not working when removing the duplications.
Heres is my select
<select ng-options="item.region as item.region for item in items | unique: 'region'" ng-model="catFilter">
Here is my app.js
var regionSort = angular.module('regionSort', [
'regionSort.controllers'
]);
regionSort.filter('unique', function() {
return function(items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {},
newItems = [];
var extractValueToCompare = function(item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function(item) {
var valueToCheck, isDuplicate = false;
var count = 0;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
Does anybody have any idea how should I solve this? Thanks in advance!!
Item structure is pretty simple like :
[
{
"name": "Name",
"desc": "Description",
"price": 700,
"priceold": 1080,
"persons": 10,
"discount": 35,
"vote": "9,3",
"image": "https://someige.jpg",
"url": "http://someurl.com",
"region": "XXX"
}, ...
]

Dynamic angular chart

I'm trying to create a dynamic chart from userTemplate object.
I'm using this directive angular-flot and I want create the dataset and options of directive dynamically.
Its work but I have this error
Error: [$rootScope:infdig] http://errors.angularjs.org/1.2.21/$rootScope/infdig?p0=10&p1=%5B%5B%22fn%3…ection%5C%22%3A%7B%5C%22color%5C%22%3A%5C%22%2354728c%5C%22%7D%7D%22%5D%5D
at Error (native)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:6:450
at k.$get.k.$digest (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:110:66)
at k.$get.k.$apply (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:112:173)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:122:253
at e (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:37:440)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:41:120
HTML
<div ng-repeat="panel in row.panels" class="{{panel.columnClass}}" resizable id="{{panel.id}}" r-directions="['right']">
<flot dataset="getDataForChart(panel)" options="getOptionForChart(panel)" height="{{panel.graph.height}}"></flot>
</div>
CONTROLLER
$scope.userTemplate = [
{
blockId: 'blockUno',
title: 'Block title',
rows: [
{
rowId: 'rowUno',
title: 'Row Title 1',
panels: [
{
id: 'palel-report-1',
title: 'uno',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
},
{
id: 'palel-report-2',
title: 'due',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "PIE",
countBy: "status"
}
},
{
id: 'palel-report-3',
title: 'tre',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
}
]
}
],
tables: []
}
];
$scope.getDataForChart = function(panel) {
var graphData = [];
var countBy = panel.graph.countBy;
var arr = $scope.reportingData;
for (var i = 0; i < arr.length; i++) {
var valueOfkey = arr[i][countBy];
graphData.push(valueOfkey);
}
var a = [], b = [], prev;
graphData.sort();
for (var i = 0; i < graphData.length; i++) {
if (graphData[i] !== prev) {
a.push(graphData[i]);
b.push(1);
} else {
b[b.length - 1]++;
}
prev = graphData[i];
}
var graphData = [];
for (var i = 0; i < a.length; i++) {
var singleO = {label: '' + a[i], data: [[i, b[i]]]};
graphData.push(singleO);
}
return graphData;
};
$scope.getOptionForChart = function(panel) {
var options = angular.copy($scope.defaultPlotOptions);
var typeGraph = panel.graph.type;
switch (typeGraph) {
case "BAR":
options.series.bars.show = true;
break;
case "LINE":
options.series.lines.show = true;
break;
case "PIE":
options.series.pie.show = true;
break;
case "POINT":
options.series.points.show = true;
break;
case "TABLE":
break;
}
return options;
};
The error you get is from an infinite digest loop.
In a couple of places you are calling functions that return new items each time. Here's an example from the docs linked from the error message you received that suggests this may cause this error:
One common mistake is binding to a function which generates a new
array every time it is called. For example:
<div ng-repeat="user in getUsers()">{{ user.name }}</div>
$scope.getUsers = function() { return [ { name: 'Hank' }, { name: 'Francisco' } ]; };
Since getUsers() returns a new array, Angular
determines that the model is different on each $digest cycle,
resulting in the error. The solution is to return the same array
object if the elements have not changed:
var users = [ { name: 'Hank' }, { name: 'Francisco' } ];
$scope.getUsers = function() { return users; };
In your code, you are doing the same binding to getDataForChart and getOptionForChart.

jqplot - set custom color for bar charts based on label name

I have a backbone app that dynamically renders multiple bar charts with different data sets and I have no way of knowing which label name will show up. For example, if given a set of labels: "strawberry", "vanilla", "chocolate", I would like to set the color for "strawberry" to pink every time that category shows up in a graph.
Is there a way to set a specific color on a bar based upon its label value?
Here is my current code:
collectCategories: function(aggregates) {
var categories = {};
_.each(aggregates, function(aggregate) {
for (var category in aggregate) {
categories[category] = true;
}
});
categories = _.keys(categories);
categories.sort();
return categories;
},
render: function() {
var container = this.$el;
container.empty();
var aggregates = this.collection.map(function(purchase) {
return purchase.aggregates();
});
var categories = this.collectCategories(aggregates);
var datasets = _.map(categories, function(category) {
var row = _.map(aggregates, function(aggregate) {
var qtyInCategory = aggregate[category];
return qtyInCategory ? qtyInCategory : 0;
});
return row;
});
var labels = this.collection.map(function(purchase) {
return purchase.get('purchase_date').substr(0, 10);
});
if (datasets.length > 0) {
this.renderPlot(datasets, labels, categories);
}
return this;
},
renderPlot: function(datasets, labels, categories) {
var seriesLabels = _.map(categories, function(category) {
return { label: category};
});
var customSeriesColors =
var plot = $.jqplot('bar-charts-container', datasets, {
stackSeries: true,
captureRightClick: true,
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {
barMargin: 30,
varyBarColor: true
},
pointLabels: {
show: false
}
},
series: seriesLabels,
seriesColors:
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: labels
},
yaxis: {
padMin: 0
}
},
legend: {
show: true,
location: 'e',
placement: 'outside'
}
});
Since you have access to your labels when you plot, why not just define the colours there too?
seriesColors: colorsForLabels(seriesLabels)
Elsewhere in the object:
colorsForLabels: function(labels) {
return _.map(labels, function(labelObj) {
switch (labelObj.label) {
case 'strawberry':
return 'pink';
case: 'vanilla':
return 'white';
default:
# return a random colour from a list
}
});
}
The default is an open question; if you could have labels that don’t match the predefined list, you’ll have to choose from a list of alternates.

ExtJS4: this.ownerCt in initComponent function

Is there any way to access the parent component (via this.ownerCt) in the initComponent function?
While trying to access it via this.ownerCt, i found out that the ownerCt attribute is set after initComponent. So I do not know how i can hook in the initialization process of my component where i can change some parent's attributes.
I know this doesn't answer the question directly. I would have placed this in the comments to your question but I'm not allowed yet it would appear. If you are building breadcrumbs. I would look at extending the tab panel and creating a plugin for the Tab Bar that creates the kinda of navigation you want.
Ext.define('HOD.plugins.Breadcrumbs', {
// private
init : function(tabBar) {
tabBar.on('beforeadd', this.addIcons, this);
tabBar.on('beforeremove', this.handleTabRemove, this);
},
addIcons: function(tabBar, newTab, index, options) {
if (index > 0) {
newTab.iconCls = 'icon-arrow';
tabBar.items.each(function(tab) {
if (tab != newTab) {
tab.overCls = 'breadcrumbs-over'
}
});
}
},
handleTabRemove: function(tabBar, oldTab, options) {
var count = tabBar.items.getCount();
if (count > 1) {
var newTab = tabBar.items.getAt(count-2);
newTab.overCls = '';
newTab.removeCls('x-tab-breadcrumbs-over');
}
}
});
Then extend the tab panel so it uses the above plugin to style the tabs correctly.
Ext.define('HOD.view.GlobalNavigation', {
extend: 'Ext.tab.Panel',
border: false,
alias: 'widget.content',
requires: ['HOD.plugins.Breadcrumbs'],
tabBar: {
cls: 'breadcrumbs',
plugins: ['tabbarbreadcrumbs']
},
initComponent: function() {
this.on('tabchange', this.handleTabChange, this);
this.callParent(arguments);
},
push: function(tab) {
this.add(tab);
this.setActiveTab(tab);
},
pop: function() {
// Get the current cards;
var cards = this.getLayout().getLayoutItems();
if (cards.length > 1) {
this.setActiveTab(cards[cards.length-2]);
}
},
handleTabChange: function (tabPanel, newCard, oldCard, options) {
var cards = tabPanel.getLayout().getLayoutItems();
for (var i = (cards.length - 1); i > 0; i--) {
if (cards[i] !== newCard) {
this.remove(cards[i]);
} else {
break;
}
}
}
});
I've written up post about it here if you need more detail.
I would not recommend changing anything in the container from the inside element functions. Instead I would create an event in the element, fire that event and listen for it in the container.
This way your component will notify the container to do something, and container will do it itself.

Resources