I need to create a ListModel, that contains an object (string and bool inside) statically.
If I add to an empty ListModel element by using append - all works well.
property ListModel qwe: ListModel {}
var imageToAdd { value: "picture.png", imageType: 1 }
qwe.append({
text: "TextToAdd",
image: imageToADD,
position: 1
})
// This works correct
But I need to create ListModel statically and it doesn't work.
ListModel {
ListElement {
text: "TextToAdd"
image: { value: "Qwer.png", imageType: 1 } // <-- This doesn't work
position: 1
}
}
How it should look like?
A ListElement in Qt must have values of type string, bool, numbers or enum. More complex datatypes like hashmaps are not allowed.
You can read this deep down in the Qt 5.2 sourcecode: qqmllistmodel.cpp. This didn't change since the Qt 4.7 times.
List elements are defined inside ListModel definitions, and represent items in a
list that will be displayed using ListView or Repeater items.
List elements are defined like other QML elements except that they contain
a collection of role definitions instead of properties. Using the same
syntax as property definitions, roles both define how the data is accessed
and include the data itself.
The names used for roles must begin with a lower-case letter and should be
common to all elements in a given model. Values must be simple constants; either
strings (quoted and optionally within a call to QT_TR_NOOP), boolean values
(true, false), numbers, or enumeration values (such as AlignText.AlignHCenter).
However, a ListModel seems to be capable to store all types defined in the ECMA-262 standard: The primitive types, which are Undefined, Null, Boolean, Number, and String as well as the Object type.
Edit: If you want to create the elements in QML, you have to rewrite your code to something like
ListModel {
ListElement {
text: "TextToAdd"
imageValue: "Qwer.png"
imageType: 1
position: 1
}
}
Edit2: Or you go the Javascript way. Create an empty model first and fill it on start
ListView {
model: ListModel { id: qwe }
delegate: ...
Component.onCompleted: {
qwe.append({
text: "Image 1",
image: { value: "picture.png", imageType: 1 },
position: 1
});
qwe.append({
text: "Image 2",
image: { value: "picture.png", imageType: 1 },
position: 2
});
qwe.append({
text: "Image 1",
image: { value: "picture.png", imageType: 1 },
position: 3
});
}
}
model: ListModel {
ListElement {
name: "My Name"
image: ListElement {
src: "My src"
}
}
}
You can access it in for example a delegate:
image.get(0).src
I would asume you should be able to access it via image.src but that doesn't work...
Related
I wonder if there is a way to achieve dependsOn option for a Types.Relationship field in KeystoneJS.
Example:
Event.add({
category: { type: Types.Relationship, ref: 'EventCategory' },
singer: { type: String, dependsOn: { category: { type: 'concerts' } } },
});
Currently, I can only walk around this by manually set dependsOn to the id of the related field.
I'm trying to group this object by name, so in fine I would be able to distinguish all names 'duval' from 'lulu':
const groupName = R.groupBy(R.prop('name'), [data]);
But this won't work on:
let data = {
benj: {
content : undefined,
name : 'duval',
complete: false,
height : 181
},
joy: {
content : undefined,
name : 'duval',
complete: true
},
kaori: {
content : undefined,
name : 'lulu',
complete: true
},
satomi: {
content : undefined,
name : 'lulu',
complete: true
}
}
Should I change the format of my object, or is there a way to do it in this kind of object ?
Passing [data] to groupBy is not going to help much. You want to group a list containing a single item. The fact that that item has properties like 'bennj' and 'joy' rather than 'name' is only part of the issue.
You can get something that will work, I think, if this output would be useful:
{
duval: {
benj: {
content: undefined,
name: "duval",
complete: false,
height: 181
},
joy: {
content: undefined,
name: "duval",
complete: true
}
},
lulu: {
kaori: {
content: undefined,
name: "lulu",
complete: true
},
satomi: {
content: undefined,
name: "lulu",
complete: true
}
}
}
But it's a bit more involved:
compose(map(fromPairs), groupBy(path([1, 'name'])), toPairs)(data)
toPairs converts the data to a list of elements something like this:
[
"benj",
{
complete: false,
content: undefined,
height: 181,
name: "duval"
}
]
then groupBy(path[1, 'name']) does the grouping you're looking to do, by finding the name on the object at index 1 in this list.
And finally map(fromPairs) will turn these lists of lists back into objects.
It's not a particularly elegant solution, but it's fairly typical when you want to do list processing on something that's not really a list.
I'm trying just now to implement a list with complicated data. In my case it should be an array like this:
[
{ item: "itemName1", objects: [x1,x1,x1] },
{ item: "itemName2", objects: [x2,x2,x2] }
]
As I know there are 2 ways to do that. First of them is to expose QObjectList-based model from C++ to QML. Than currently not interested for me since I want to implement that in pure QML. But ListElement's roles must contain only simple constants, line strings, numbers etc. i.e. no arrays.
So I did the data source as external array:
import QtQuick 2.5
import QtQuick.Layouts 1.2
import QtQuick.Window 2.0
Window {
width: 500
height: 500
id: window
ListView {
id: listView
anchors.fill: parent
anchors.margins: 2
spacing: 2
property var data: [ { name: "item1", objects: [1,2,3]} ]
model: data.length
delegate: Rectangle {
width: parent.width
height: content.height
property int itemIndex: index
color: index % 2 ? "#EFEFEF" : "#DEDEDE"
RowLayout {
id: content
spacing: 10
Text {
text: listView.data[itemIndex].name
}
Column {
Repeater {
model: listView.data[itemIndex].objects.length
Text {
text: listView.data[itemIndex].objects[index]
}
}
}
}
}
Component.onCompleted: {
listView.data.push( { name: "item2", objects: [4,5,6] } );
listView.data.push( { name: "item3", objects: [7,8,9] } );
listView.model = listView.data.length; // it doesnt't work without this line
}
}
}
It works fine with static array. The problem appears when I fill the array dynamically. In this case the property binding (model: data.length) suddenly stops working. So the workaround is to set it manually but I don't like this solution.
in Sencha Touch 2.1 how can I load the chart dynamically from json, also with dynamic fields store, chart axes, and chart series,
I know maybe this is too much, but I need to display many kind of data, If I create 1 chart component for each display means I have to create more than 15 chart component, I'm afraid it get bloated
I did not complete this dynamically, but I made it seem dynamic.
I first request a user to fill out a form.
I also have multiple panels that holds charts with empty stores, in the form of several different layouts.
Based on the user's form, I show and hide panels, or chart when they need to be displayed only after loading the store with the required data.
yes it is bulky, and they are static, but I found it slightly easier to handle than dynamically loading.
EDIT
After thinking,
have you tried a function like
function dynamiccharts(var1, var2, var3){
return Ext.chart.Chart({
....
})
}
variables would include things like data, url, store or etc.
This is my example creating a chart on controller inside a panel: axis, series, store fields, url are became parameters, PAR_FORM is global variable showing the difference between views, I'm using this code for another chart (Column, Pie)
Ext.define("Geis.controller.app", {
extend: "Ext.app.Controller",
config: {
refs: {
mainview: 'mainview',
barchartview: 'barchartview',
btnShowChartAnggaran: '#btnShowChartAnggaran'
},
control: {
'btnShowChartAnggaran': {
tap: 'onShowChartAnggaran'
}
}
}
createBarChart: function(fields, series_xfield, series_yfield, url) {
this.getBarchartview().add(new Ext.chart.CartesianChart({
id: 'barchartgenerateview',
store: {
fields: fields,
proxy: {
type: 'jsonp',
url: url
}
},
background: 'white',
flipXY: true,
colors: Geis.view.ColorPatterns.getBaseColors(),
interactions: [
{
type: 'panzoom',
axes: {
"left": {
allowPan: true,
allowZoom: true
},
"bottom": {
allowPan: true,
allowZoom: true
}
}
},
'itemhighlight'
],
series: [{
type: 'bar',
xField: series_xfield,
yField: series_yfield,
highlightCfg: {
strokeStyle: 'red',
lineWidth: 3
},
style: {
stroke: 'rgb(40,40,40)',
maxBarWidth: 30
}
}],
axes: [{
type: 'numeric',
position: 'bottom',
fields: series_yfield,
grid: {
odd: {
fill: '#e8e8e8'
}
},
label: {
rotate: {
degrees: -30
}
},
maxZoom: 1
},
{
type: 'category',
position: 'left',
fields: series_xfield,
maxZoom: 4
}]
}));
Ext.getCmp('barchartgenerateview').getStore().load();
},
onShowChartAnggaran: function() {
this.getBarchartview().remove(Ext.getCmp('barchartgenerateview'), true);
if (PAR_FORM == 'Dana Anggaran') {
this.createBarChart(['kode', 'keterangan', 'nilai'], 'keterangan', 'nilai',
Geis.util.Config.getBaseUrl() + 'anggaran/laporan/json/get_dana_anggaran_json/');
} else if (PAR_FORM == 'Alokasi Anggaran') {
this.createBarChart(['kode', 'keterangan', 'belanja_pegawai', 'belanja_barang', 'belanja_modal'],
'keterangan', ['belanja_pegawai', 'belanja_barang', 'belanja_modal'],
Geis.util.Config.getBaseUrl() + 'anggaran/laporan/json/get_alokasi_json/');
}
this.getMainview().animateActiveItem(1, {type:'slide', direction:'left'});
}
});
base on my experiment if you want to activate the interactions features you need to set the chart id dynamically too, for example by creating Global Counter Variable
In dojo 1.7.2, if I create a data store containing array values, dojox.grid.DataGrid displays them with no problem, separating each item with a coma.
However, in dojo 1.6, it takes only the first element of my array. I have a project where I have to use version 1.6. Is there any workaround for this in that version ?
To illustrate the problem, here are 2 examples :
On dojo 1.6 : http://jsfiddle.net/psoares/HbFNY/
On dojo 1.7 : http://jsfiddle.net/psoares/QLm65/
Thanks !
Apparently the problem comes from ItemFileReadStore rather than from the grid.
I modified my code for 1.6 to use ObjectStore and MemoryStore instead, and it worked.
See http://jsfiddle.net/psoares/HbFNY/16/
this is a flaw and yet it is not.. The construct of your JSON is not quite right as any value is not allowed as array unless it is one of the childAttrs. Due to nature of [1,2,3].toString() that is why your attempts on setting values as arrays are considered valid.
The get/set in an ItemFileReadStore works with its items as such:
store._arrayOfAllItems = {
value1 : { values : [ 'realvalue' ] },
value2 : { values : [ 'realvalue' ] }
};
the getter then says
store.get = function(itemById, val) { return itemById[val][0]; }
// why only the first arrayslot is pulled from store---/^
In your JSON construct, what prohibits you from settings the values as such following?
var data = {
id: 'id',
label: 'id',
items: [
{
id: "value1",
values: "a,b,c" // permit-able string value
},
{
id: "value2",
values: "foo"}
]
};
If you want multiple values by same key of one ID then you must deliver the data as children and handle them as such, like;
data: {
id: 'id',
label: 'id',
childrenAttrs: [ 'items', 'children'], // << default behavior
items: [ {
id: "value1",
children: [
{ id: "value1_1", values: 'a' },
{ id: "value1_2", values: 'b' },
{ id: "value1_3", values: 'c' }
]
}, {
id: "value2",
values: "foo"
} ]
}
However, only the dojox.grid.TreeGrid will allow using multi-lvl datastores