select a field in store - sencha-touch

hi can anyone tell ho to selct a field in a store
i made a nestedlist and i want when someone clicks on a leaf the message somes oops, you click on a leaf. and leaf is a boolean field.
this is what i have:
new Ext.NestedList({
title: 'Categorieën',
store: NestedListDemo.Groepen_Store,
flex: 1,
listeners:
{
itemtap: function(item)
{
if (leaf==true)
{
Ext.Msg.alert('Oops', 'leaf clicked', Ext.emptyFn);
}
}
}
}),
but i have no idea how to do that with sencha touch.

I'm a little confused about where this leaf property exists. If you take a look at the documents for the NestedList, you will see that there is both an itemtap and a leafitemtap event that the list will fire. My recommendation would be to use the leafitemtap to only get events on the items which are leafs.
So if you alter your code using that function:
listeners:{
leafitemtap: function(sublist, index, element, event, card){
Ext.Msg.alert('Oops', 'leaf clicked', Ext.emptyFn);
//find the item
var item = sublist.store.getAt(index);
//then you can do something with the item
//item.get('leaf')
//sublist.store.remove(item)
}
}

Related

Dojo dijit tree with checkbox is not keyboard accessible

I have created a dijit.Tree object where every node is a checkbox. When you select/deselect the parent node, the child nodes get selected/deselected;
when one of the children is deselected, the parent gets deselected; when all the children are selected, the parent gets selected. It works perfectly fine.
However I need it to be keyboard accessible. When I navigate to the tree nodes and press spacebar or Enter, nothing happens.
I tried adding tabindex and aria-role to the checkbox (programmatically), but it did not work.
Here is the fiddle - http://jsfiddle.net/pdabade/pyz9Lcpv/65/
require([
"dojo/_base/window", "dojo/store/Memory",
"dijit/tree/ObjectStoreModel",
"dijit/Tree", "dijit/form/CheckBox", "dojo/dom",
"dojo/domReady!"
], function(win, Memory, ObjectStoreModel, Tree, checkBox, dom) {
// Create test store, adding the getChildren() method required by ObjectStoreModel
var myStore = new Memory({
data: [{
id: 'allDocuments',
name: 'All Documents'
}, {
id: 'inboxDocuments',
name: 'Inbox Documents',
parent: 'allDocuments'
}, {
id: 'outboxDocuments',
name: 'Outbox Documents',
parent: 'allDocuments'
}, {
id: 'draftDocuments',
name: 'Draft Documents',
parent: 'allDocuments'
}, {
id: 'finalDocuments',
name: 'Final Documents',
parent: 'allDocuments'
}],
getChildren: function(object) {
return this.query({
parent: object.id
});
}
});
// Create the model
var myModel = new ObjectStoreModel({
store: myStore,
query: {
id: 'allDocuments'
}
});
// Create the Tree.
var tree = new Tree({
model: myModel,
autoExpand: true,
getIconClass: function(item, opened) {
// console.log('tree getIconClass', item, opened);
// console.log('tree item type', item.id);
},
onClick: function(item, node, event) {
//node._iconClass= "dijitFolderClosed";
//node.iconNode.className = "dijitFolderClosed";
var _this = this;
console.log(item.id);
var id = node.domNode.id,
isNodeSelected = node.checkBox.get('checked');
dojo.query('#' + id + ' .dijitCheckBox').forEach(function(node) {
dijit.getEnclosingWidget(node).set('checked', isNodeSelected);
});
if (item.id != 'allComments') {
if (!isNodeSelected) {
var parent = node.tree.rootNode; // parent node id
//console.log(node);
parent.checkBox.set('checked', false);
} else {
var parent = node.tree.rootNode;
var selected = true;
var i = 0;
dojo.query('#' + parent.id + '.dijitCheckBox').forEach(function(node) {
if (i > 0) {
var isSet = dijit.getEnclosingWidget(node).get('checked');
console.log(isSet);
if (isSet == false) {
selected = false;
}
}
i++;
});
if (selected) {
parent.checkBox.set('checked', true);
}
}
}
//console.log(node.id);
},
_createTreeNode: function(args) {
var tnode = new dijit._TreeNode(args);
tnode.labelNode.innerHTML = args.label;
console.log(args);
var cb = new dijit.form.CheckBox({
"aria-checked": "false",
"aria-describedby": args.label
});
cb.placeAt(tnode.labelNode, "first");
tnode.checkBox = cb;
return tnode;
}
});
tree.placeAt(contentHere);
tree.startup();
tree.checkedItems();
//tree.expandAll();
});
}
Any ideas as to how to make it keyboard accessible?
Thanks!
Looking into the dijit/Tree source I see that it sets the function _onNodePress() as an event handler for keyboard events. You can override it (or add an aspect after it) and handle the key presses you want manually. It takes as argument the tree node and an event object that you can use to check specifically for the space and the enter key.
I forked your jsfiddle with an example: https://jsfiddle.net/pgianna/jjore5sm/1/
_onNodePress: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
// This is the original implementation of _onNodePress:
this.focusNode(nodeWidget);
// This requires "dojo/keys"
if (e.keyCode == keys.ENTER || e.keyCode == keys.SPACE)
{
var cb = nodeWidget.checkBox;
cb.set('checked', !cb.get('checked'));
}
}
Do not add role, aria-checked, nor tabindex to the checkbox. Those are already built into the control, so you are adding risk of breaking it down the road. You can probably also get rid of every role="presentation" as those are on <div>s and <span>s which are presentational by nature. Finally, you need <label> on each block of text that is associated with a checkbox if you want this to be accessible. The aria-describedby is incorrect and is the less good option anyway.
I am getting the error: Uncaught TypeError: tree.checkedItems is not a function (line 159)
You also have a big focus management problem. Put the following in your CSS and you will see that it takes two presses of the Tab key for each single control (if starting at a focused checkbox): :focus {outline:2px solid #f00;}
It looks like you have the containing elements stealing any clicks, meaning the correct element never gets selected. The <span> with classes dijit dijitReset dijitInline dijitCheckBox keeps stealing focus as it toggles its tabindex from -1 to 0, taking itself in and out of the tab order. That may be a factor.
I suggest addressing the script error and then looking at focus management.
With dijit, there's all kinds of stuff going on in the background that might be out of your control. As aardrian said, there's lots of role=presentation and all the aria tags on the <input type='checkbox> are superfluous. dijit is probably (incorrectly) setting all that. An <input type='checkbox> already handles selections and it's role is inherently a checkbox. Those aria properties are for when you're making a custom checkbox out of div/span tags.
There is a native checkbox buried down in the code but it has opacity set to 0 so you can't see it. dijit is probably using it for the checkbox events.
The native checkbox also has data-dojo-attach-event="ondijitclick:_onClick". I'm not sure what that means but anytime I see "click" in an event name, I get suspicious that it might not work with a keyboard.
I tried the example on https://dojotoolkit.org/reference-guide/1.10/dijit/form/CheckBox.html and it works with the keyboard. Hit space will check and uncheck the box. Whether you can see the focus on the checkbox is another issue.
As a side note, it might be nice if your checkbox tree used aria-checked="mixed" for the parent branch. Anytime you have child checkboxes where some are selected and some are not, you can use "mixed" for the parent checkbox to indicate a mixture of selections. Not sure if dijit supports that.

sencha touch 2 - how to manipulate history support

i want to use the routing system to provide back-button support. i am showing a list of items based on a record store. when i handle the itemtap event function(list, index, target, record) i get a reference to the selected record which i pass to a new screen which i instantiate and show.
under this scenario, how do i instruct the history manager that i have moved to a new screen and enable the back button. i see application.redirectTo but i would lose my reference to the record i want to use. (redirectTo will push a new action into the history stack that includes the primary id of the record but that seems redundant as i would then need re-find the record based on the id when i handle the redirect.)
is there a direct way to tell the history object to advance to a new action and also enable back button support?
I didn't find how to do it easier. Here's how I do it in my application (with nested list).
I created controller with routing like this:
Ext.define('MyApp.controller.ListItems', {
extend: 'Ext.app.Controller',
config: {
refs: {
nestedList: '.nestedlist'
},
control: {
nestedList: {
itemtap: 'itemSelected'
}
},
routes: {
'item/:id': 'showListItem'
}
},
list: null,
index: null,
target: null,
record: null,
showListItem: function( id ){
var nestedList = this.getNestedList(),
store = nestedList.getStore(),
node = store.getById(id);
if ( node.isLeaf() ){
nestedList.goToLeaf(node);
nestedList.fireEvent('leafitemtap', nestedList, this.list, this.index, this.target, this.record);
} else {
nestedList.goToNode(node);
}
},
itemSelected: function( nl, list, index, target, record ){
this.list = list;
this.index = index;
this.target = target;
this.record = record;
var path = 'item/'+record.data.id;
this.redirectTo(path);
}
});
I've also overriden onItemTap method of nested list for all list changes now is done via controller & propper routing.
onItemTap: function(list, index, target, record, e){
this.fireEvent('itemtap', this, list, index, target, record, e);
}
Hope it'll be helpful.
Write here, if you find better way, please.

Nested List refresh

Any one knows how to refresh a nested list?
I am creating a list. On tap of an item it loads a nested list. if i traverse in a nested list and then tap to another item and come back to the prev item, its still stuck in the place where it was last left.
I tried using
Ext.getCmp('nestedList').refresh();
but thet doesn seem to work.
Below is my code for the nested list panel.
Ext.define("InfoImage.view.nestedList", {
extend:'Ext.NestedList',
xtype:'nestedList',
id:'nestedList',
config:{
fullscreen:'true',
title:'Work Items Task 1',
// ui:'normal',
xtype:'nestedList',
displayField : 'text',
store:'nestedListStore',
style: {
'background-color': 'rgba(0,140,153,0.1)'
}
}
});
and the code for loading the nested list is:
showListDetail : function(view, index, item, record) {
var rec = view.getStore().getAt(index);
// Ext.getStore('workItemStore').add({Task: '7'
// },{Server: 'mobcomp1'});
if (index == 0) {
this.getDocPanel().animateActiveItem(
this.getNestedPanel(), {
type : 'slide',
direction : 'up',
duration : 250
});
Ext.getCmp('nestedList').reload();
}
Any help is appreciated.
Thanks in advance.
You can't directly refresh a nestedlist. There's no refresh() or reload() method for it.
All you need to do is load the store which is used for your nestedlist using it's configured proxy.
this.store.setProxy({
// proxy configurations ...
// ......
// ......
});
this.store.load();

Sencha Touch - setactiveitem to top level on nested list

I have a tabpanel with items of nestedlists. Each nested list goes several levels deep. If I drill down one of the nested list, then i click on a different item in the tabpanel, then click back to it, the nested list is still drilled down, instead of refreshing to the top level of the nested list.
How do I get the nestedlist to display the top level instead of the drilled down level everytime I return to it?
Additional Info
OK, I'm part way there. Here's the code I have now:
var tabBar = new Ext.TabPanel({
fullscreen: true,
id : 'footer',
cardSwitchAnimation:false,
listeners: {
cardswitch: {
fn: function() {
Ext.getCmp('footer').getActiveItem().setActiveItem(0);
}
}
},
tabBar: {
dock: 'bottom'
},
items: [/* some nestedlist components */]
});
So the final problem is that everytime I cardswitch, I see the "drillup/slideback" animation of the nested list sliding back or drilling back to the top level item. How do I get it to just show the top level item without this drill up/slide back animation? I want to preserve the slide forward and drill down animation when the user drills down the nestedlist.
You can try to set the cardSwitchAnimation parameter to false in the setActiveItem method
[UPDATE] Deselect item
Add an event listener for the item tap event on the nested list
nestedList.on("itemtap", function(nestedlist, index, item, e){setTimeout(function(){nestedlist(index);},500);}, this);
[UPDATE] From John
For some reason your code didn't do anything for me. But this one worked:
var nestedList = new Ext.NestedList({
store: store,
listeners: {
itemtap: function(dv, ix, item, e) {
// Clear the selection soon
setTimeout(function(){dv.deselect(ix);},500);
}
}
});
In March 2014, with version 2.3.1, I had the above problem with the Ext.dataview.NestedList object. The suggested approach of using the "deselect" method did not work for me - probably because of the two years that have gone by since the original question.
To resolve problem, I used the following:
nestedList.goToNode( nestedList.getStore().getRoot() );

sencha touch - nestedlist - store all the fields' values of "activeItem of nestedlist"

i have a panel which should show the "description" field of "currently activeitem of nestedlist". nestedlist uses the model having fields:
id
text
description
when user taps on any item of nestedList [on selectionchange OR itemtap&backtap], i want to change description in the panel with description of "currently activeItem of nestedList".
Is this possible?
thanks for any help/solution/pointer.
The same problem I had today, and no solution had been found with a nested list, because no single field can be taken from a Ext.data.TreeStore. One solution could be that you have lots of "if-function 'do with all the ID's and then you give each ID a text. But that's not good.
I've decided to make a simple list.
if you want I can show you my solution for the simple list
ps.: I use Sencha Touch 1.1
Update:
NotesApp.views.NaviList = new Ext.List({
fullscreen: true,
flex: 1,
layout: 'card',
scroll: false,
useToolbar: false,
itemTpl: '{text}',
store: store,
listeners: {
itemtap: function (obj, idx, el, e) {
var record = this.store.getAt(idx);
var tle = record.get('text');
index = record.get('index');
NotesApp.views.notesListContainer.setActiveItem(index, { type: 'slide', direction: 'left' });
}
}
}
});
description:
My App has the name: "NotesApp".
"notesListContainer" is a Container where all my List are displayed. "index" is an ID that I get from the store and the calls list.
Now when you tap on my NaviList you set a new ActiveItem in this Container.
thanks a lot for the reply. I also tried using simple list with one Ext.button(back button in case of nestedlist). On itemtap and buttonclink, i change list's content by
var t = new Ext.data.Store and list.setStore(t).
Please let me know if there is any other better option to do it.