Updating Child Panels in Sencha Touch MVC App - model-view-controller

Developing a Sencha Touch MVC app that pulls data from json store (thats set up to a DB pulling out content from a Wordpress Blog).
Everything works up until my "detail" panel. Instead of it listening to the TPL, its just dumping some data. The data looks similar to my blog post, but is filled with other code and doesn't make much sense.
Here is a lean version of my list:
myApp.views.PostListView = Ext.extend(Ext.Panel, {
postStore: Ext.emptyFn,
postList: Ext.emptyFn,
id:'postlistview',
layout: 'card',
initComponent: function () {
/* this.newButton = new Ext.Button({
text: 'New',
ui: 'action',
handler: this.onNewNote,
scope: this
});*/
this.topToolbar = new Ext.Toolbar({
title: 'All Posts',
/* items: [
{ xtype: 'spacer' },
this.newButton
],*/
});
this.dockedItems = [ this.topToolbar ];
this.postList = new Ext.List({
store: myApp.stores.postStore,
grouped: true,
emptyText: '<div style="margin:5px;">No notes cached.</div>',
onItemDisclosure: true,
itemTpl: '<div class="list-item-title">{title}</div>' +
'<div class="list-item-narrative"><small>{body}</small></div>',
});
this.postList.on('disclose', function (record) {
this.onViewPost(record);
}, this),
this.items = [this.postList];
myApp.views.PostListView.superclass.initComponent.call(this);
},
onViewPost: function (record) {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewpost',
post: record
});
},
});
And here is the "detail" view that is called on disclosure:
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
title:'Single Post',
id:'postsingleview',
layout:'card',
style:'background:grey;',
initComponent: function () {
this.new1Button = new Ext.Button({
text: 'Back',
ui: 'back',
handler: this.onViewList,
scope: this,
dock:"left"
});
this.top1Toolbar = new Ext.Toolbar({
items: [
this.new1Button
],
title: 'Single Posts',
});
this.postSinglePanel = new Ext.Panel({
layout:'fit',
flex:1,
scroll: 'vertical',
style:'padding:10px;background:yellow;',
itemTpl: '<tpl for=".">' +
'<div class="list-item-narrative">{body}</div>' +
'</tpl>',
});
this.dockedItems = [ this.top1Toolbar, this.postSinglePanel ];
myApp.views.PostSingleView.superclass.initComponent.call(this);
},
onViewList: function () {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewlist',
});
},
});
And here is the controller that its talking to:
Ext.regController('masterController', {
'index': function (options) {
if (!myApp.views.mainView) {
myApp.views.mainView = new myApp.views.MainView();
}
myApp.views.mainView.setActiveItem(
myApp.views.postView
);
},
'viewpost': function (options) {
myApp.views.postSingleView.postSinglePanel.update(options.post);
myApp.views.postView.setActiveItem(
myApp.views.postSingleView,
{ type: 'slide', direction: 'left' }
);
},
});
myApp.controllers.masterController = Ext.ControllerManager.get('masterController');
When the data comes out, it looks similar to this:
http://i.imgur.com/QlQG8.png
(the black boxes are "redacted" content, no error code there).
In closing, I believe that the controller is "dumping" the data into "MyApp.views.PostSingleView" rather than formatting it as I request in the TPL, though I'm not sure how to fix it. Any and all help MUCH appreciated!
UPDATE: As requested, here is the RegModel:
Ext.regModel("CategoryModel", {
fields: [
{name: "id", type: "int"},
{name: "title", type: "string"},
{name: "body", type: "string"},
],
hasMany: {
model: 'Post',
name: 'posts'
}
});
And here is a sample of the json:
{
   "status":"ok",
   "post":{
      "id":1037,
      "type":"post",
      "slug":"post-title",
      "url":"http:\/\/localhost:8888\/jsontest\/PostTitle\/",
      "status":"publish",
      "title":"Post Title",
      "title_plain":"Post Title",
      "content":"<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<br \/>\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<\/p>\n<!-- PHP 5.x -->",
      "excerpt":"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat [...]",
      "date":"2011-07-29 14:17:31",
      "modified":"2011-08-30 01:33:20",
      "categories":[
         {
            "id":87,
            "slug":"the-category",
            "title":"The Category",
            "description":"",
            "parent":17,
            "post_count":5
         }
      ],
      "tags":[
      ],
      "author":{
         "id":2,
         "slug":"tom",
         "name":"tom",
         "first_name":"tom",
         "last_name":"",
         "nickname":"",
         "url":"",
         "description":""
      },
      "comments":[
      ],
      "attachments":[
      ],
      "comment_count":0,
      "comment_status":"open"
   },
   "previous_url":"http:\/\/localhost:8888\/jsontest\/next-post\/",
   "next_url":"http:\/\/localhost:8888\/jsontest\/prev-post\/"
}

Use the tpl config option of the Ext.Panel not the itemTpl which doesn't exist.
As someone has mentioned before, be careful when using a Model instance and the update method, you will need to use the model's data property.

Try using this:
myApp.views.postSingleView.postSinglePanel.update(options.post.data);
the reason is that post does not actually expose the underlying data directly, you need to use the property data for that.
Also any particular reason why you are docking the postSinglePanel? I would be very careful using too many docked items as they are a known source of bugs and layout issues.

A simple way is to write your own method to update child panels (you can also see to override the default update method)
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
initComponent: function () {
// [...]
},
// [...]
myUpdate: function(data) {
this.postSinglePanel.update(data);
this.doComponentLayout(); // not sure if necessary...
}
});
and from your controller:
Ext.regController('masterController', {
// [...]
'viewpost': function (options) {
myApp.views.postSingleView.myUpdate(options.post.data); // note the .data
// [...]
},
});

Related

dijit/form/Select onSelect event

Are there other events that can be registered with dojo/form/Select, except onChange?
I'd need to execute a callback function every time user selects an option, even though he selects the same option as it was selected last time. The options I have tried: onSelect, onClick did not work.
var spatialSelectionStore = new Memory({
data: [
{ label: "Rectangle", id: "RECT" },
{ label: "Polygon", id: "POLY" },
{ label: "Circle", id: "CIRC" },
{ label: "Freehand", id: "FREE" }
]
});
var os = new ObjectStore({ objectStore: spatialSelectionStore });
spatialQuerySelect = new Select({
id: "selectionType",
style: { width: "100px" },
store: os,
onChange: activateDrawTool
}, "cp_selectByShapeId");
spatialQuerySelect.startup();
I found a way to do this, and while it may not be the best way to do it, it seems to work.
I set up an aspect to fire a function after the Select._setValueAttr function executes, which is fired by the widget every time you click on either the menu drop-down or a drop-down item. Because of this, I added a check to make sure the function callback only fires when you click on a menu item (i.e. after the menu has closed). I also had to delete the onChange callback you added to Select manually, as this interfered with the aspect.
HTML
<div id="foo"></div>
JavaScript
require(["dojo/aspect", "dojo/store/Memory", "dijit/form/Select", "dojo/data/ObjectStore", "dojo/dom-construct", "dojo/dom", "dojo/aspect"], function(aspect, Memory, Select, ObjectStore, domConstruct, dom, aspect) {
var spatialSelectionStore = new Memory({
data: [
{ label: "Rectangle", id: "RECT" },
{ label: "Polygon", id: "POLY" },
{ label: "Circle", id: "CIRC" },
{ label: "Freehand", id: "FREE" }
]
});
var os = new ObjectStore({ objectStore: spatialSelectionStore });
spatialQuerySelect = new Select({
id: "selectionType",
style: { width: "100px" },
store: os
}, "cp_selectByShapeId");
spatialQuerySelect.startup();
aspect.after(spatialQuerySelect, "_setValueAttr", function() {
if(spatialQuerySelect.dropDown.isShowingNow === false) {
alert(spatialQuerySelect.get('value'));
}
});
domConstruct.place(spatialQuerySelect.domNode, dom.byId("foo"), "first");
});
Fiddle
Aspects can be very powerful, but if you use too many and rely on them too heavily, you can end up with a horrible mess of spaghetti code, so I recommend you use them sparingly, and only when necessary.
In case you're not familiar with what they do, you can tell an aspect to fire before, after, or around another method, and the aspect will "listen" to that method being fired and behave appropriately with your function callback. Further documentation.
spatialQuerySelect.dropDown.on("execute",function() {
alert(spatialQuerySelect.get('value'));
});
this would also work for all option.
onExecute: function(){
// summary:
// Attach point for notification about when a menu item has been executed.
// This is an internal mechanism used for Menus to signal to their parent to
// close them, because they are about to execute the onClick handler. In
// general developers should not attach to or override this method.
// tags:
// protected
},

ExtJS4 dataView - Select node id

I have an ExtJS 4 dataView and i would like to catch the id of a selected node.
It is the first time that i'm using the dataView, then, there are some troubles.
The store is loaded correctly and i see the datas into the view very well. The problem which i'm having, concern the "classic" actions of update and delete, particularly getting the id of a selected item.
For example into a grid i click, then select a record and through a button's pressing i open a window (or other actions) with a loaded form (by sending in AJAX to the store, the id of the selected row) and i update the datas.
I'm not still able to do it with the ExtJS 4 dataView.
Below my dataView:
dataView_player = Ext.create('Ext.Panel', {
id: 'images-view',
frame: true,
collapsible: false,
autoWidth: true,
title: 'Giocatori (0 items selected)',
items: [ Ext.create('Ext.view.View', {
id:'players-view',
store: store_player,
multiSelect: true,
height: 310,
trackOver: true,
overItemCls: 'x-item-over',
itemSelector: 'div.thumb-wrap',
emptyText: 'Nessun giocatore visualizzato',
tpl: [
'<tpl for=".">',
'<div class="thumb-wrap" id="{id}-{name}">',
'<div class="thumb">',
'<img src="/img/players/{picture}" title="{name} {surname}" alt="{name} {surname}" style="">',
'</div>',
'<span class="" style="height:30px;">{general_description}{name} {surname}</span>',
'</div>',
'</tpl>',
'<div class="x-clear"></div>'
],
plugins: [
Ext.create('Ext.ux.DataView.DragSelector', {}),
Ext.create('Ext.ux.DataView.LabelEditor', {dataIndex: 'name'})
],
prepareData: function(data) {
Ext.apply(data, {
name: data.name,
surname: data.surname,
general_description: Ext.util.Format.ellipsis(data.general_description, 15)
});
return data;
},
listeners: {
'selectionchange': function(record, item, index, e) {
var node = this.getNode(record); //this.getNode(record);
console.log(node.get('id'));
}
}
}) ],
dockedItems: [{
xtype: 'toolbar',
items: [{
iconCls: 'delete',
text: 'Cancella Selezionati',
scale: 'medium',
tooltip: 'Per <b>cancellare</b> i giocatori selezionati',
tooltipType: 'qtip',
id: 'delete-player',
disabled: true,
handler: delete_news
}, '-', {
iconCls: 'edit',
text: 'Aggiorna Selezionata',
scale: 'medium',
tooltip: 'Per <b>aggiornare</b> un giocatore selezionato',
tooltipType: 'qtip',
disabled: false,
id: 'update-player',
handler: function(nodes) {
var l = nodes.get('id');
console.log(l);
}
}
}
]
}]
});
Of course, this is a wrong example (because the listeners don't work) but it's just to make an idea.
There are two main things what i would like to do:
1) Catch the id (and other store's fields) of the selected item on the action "selectionchange". Obviously, now it doesn't work because of this: node.get('id'). Of course it's a wrong syntax but make up the idea of my will.
2) Catch the id of the selected item on the handler event of the "update-player" button. As above, the issue is the nodes.get('id'). Further trouble, is how to pass the selected item's features. in handler: function(nodes) { the nodes variable does not assume any value and i don't know how to pass the params from the dataview to the handler function.
I hope that somebody will able to help me.
According to the docs the selectionchange event provides the selection model as well as the array of selected records, so you are probably assuming the wrong parameters in your listener.
Without doing further testing, I think it should be something like this:
listeners: {
'selectionchange': function(selModel, selection, eOpts) {
var node = selection[0];
console.log(node.get('id'));
}
}
Note that you're using multiSelect: true, so it could be more than one record in the selection array.
Answer for second part of the question:
In button handler, you need to get selection model of the view and from it get information about selected records:
handler: function(nodes) {
// find view component
var view = dataView_player.down('dataview');
// get all selected records
var records = view.getSelectionModel().getSelection();
// process selected records
for(var i = 0; i < records.length; i++) {
console.log(records[i].getId());
}
}

in extjs how to bind store to view which is included as item in other view

i am working in extjs. i have view as-
QbqnsResultmain.js
Ext.define('Balaee.view.qb.qbqns.QbqnsResultmain',
{
extend:'Ext.form.Panel',
requires:[
'Balaee.view.qb.qbqns.QbqnsResult'
],
id:'QbqnsResultmainId',
alias:'widget.QbqnsResultmain',
title:'Result',
height:400,
items:[
{
xtype:'QbqnsResult',
},
],
buttons:[
{
xtype:'button',
fieldLabel:'review',
action:'getreview',
name:'review',
formBind:true,
text:'Review',
},
{
xtype:'button',
fieldLabel:'papers',
action:'getpapers',
name:'papers',
formBind:true,
text:'Get all papers',
},
]});
and QbqnsResult.js-
Ext.define('Balaee.view.qb.qbqns.QbqnsResult',
{
extend:'Ext.view.View',
id:'QbqnsResultId',
alias:'widget.QbqnsResult',
//store:'kp.PollStore',
store:'qb.QbqnsStore',
config:
{
tpl:'<tpl for="1">'+
'<div id="main">'+
'</br>'+
//'<b>Question :-</b></br>'+
'<h1 id="q">Total number of Questions are:-</h1>{TotalQuestions}</br>'+
'<h1 id="q">Number of attempted Questions:-</h1> {Attempted}</br>'+
'<h1 id="q">Number of correct answers:-</h1> {CorrectAnswers}</br>'+
'<h1 id="q">Total score:-</h1> {Total}</br>'+
'<h1 id="q">Score you got is:-</h1> {Score}</br>'+
'<h1 id="q">percentage you got is:-</h1> {percentage}</br>'+
'<p>---------------------------------------------------------</p>'+
'</div>'+
'</tpl>',
itemSelector:'div.main',
}
});
On click of submit button,i want to show above view. So i had written code in controller as-
check:function()
{
var resultStore=Ext.create('Balaee.store.qb.QbqnsStore');
proxy=resultStore.getProxy();
Ext.apply(proxy.api,{
read:'index.php/QuestionBank/qbpaper/getResult',
create:'index.php/QuestionBank/qbpaper/getResult'
});
Ext.apply(proxy.reader,{
type:'json',
//root:'polls',
root:'questions'
});
Ext.apply(proxy.writer,{
type:'json',
//root:'polls',
root:'data'
});
var getdata=this.getLocalvalue();
console.log(getdata.data);
Paperno=getdata.data.questionPaperNo;
UserId=getdata.data.userId;
var answers = '{"data":[';
answers = answers + '{"paperNo":"'+Paperno+'","userId":"'+UserId+'"}';
answers =answers+']}';
console.log(answers);
resultStore.load({
params:{
data: answers
},
callback: function(records,operation,success){
console.log(records);
console.log("Successfully data send");
},
scope:this
});
var temp= Ext.getCmp('qbqnsId');
temp.removeAll();
var worldChaptor3 =temp.add({xtype:'QbqnsResultmain',
id:'QbqnsResultmainId',
store:resultStore});
},
So i want to bind resultStore to QbqnsResult view's tpl which i have included as xtype in QbqnsResultmain view. But resultStore get binded to Qbqnsresultmain view but not to Qbqnsresult which is included as item in it by means of its xtype. So how to bind store to it. Can someone guide me
One way to do it can be:
var worldChaptor3 =temp.add({xtype:'QbqnsResultmain',
id:'QbqnsResultmainId',
store:resultStore});
worldChaptor3.down('QbqnsResultmain > QbqnsResult').bindStore(resultStore);
But, it would be better if you do it in your QbqnsResultmain, i'll do it on the afterrender event, that way, you can bind the store automatically on creation.

Extjs create dynamic accordion using store

I'm beginning development of an app in extjs. I'm using the MVC approach, as provided in the extjs documentation.
I have some dynamic data which needs to present the user with a set of accordion controls. I've got the data in a store, but I do not know how to dynamically create the accordion items (unlike grid panels, there doesn't appear to be a store data method).
Here is my current accordion view code - with static items:
Ext.define('BP.view.induction.LeftPage', {
extend: 'Ext.Panel',
alias : 'widget.leftpage',
title: "Left Page",
layout: {
type: 'accordion',
align: 'stretch'
},
layoutConfig: {
// layout-specific configs go here
titleCollapse: true,
animate: true,
activeOnTop: true
},
items: [{
xtype: 'panel', // fake hidden panel, so all appear collapsed
hidden: true,
collapsed: false
},{
xtype: 'panel',
title: 'Panel 1',
html: 'Panel content!'
},{
xtype: 'panel',
title: 'Panel 2',
html: 'Panel content!'
},{
xtype: 'panel',
title: 'Panel 3',
html: 'Panel content!'
}]
});
Any guidance on how to achieve the above would be appreciated, thank you.
[Edit] In response to sra's request, here is my controller:
Ext.define('BP.controller.Induction', {
extend: 'Ext.app.Controller',
views: [
'induction.Binder'
],
stores: [
'Sections',
'Categories',
'Tasks'
],
init: function() {
console.log('Initialized Induction!');
}
});
I should note here that this controller loads a parent view, which in turn loads the LeftPage view - I'm not sure if this creates any scoping issues. Furthermore, as you can see, more than one store is loaded.
You can do like this (untested example with some tweaks)
Ext.define('BP.view.induction.LeftPage', {
extend: 'Ext.Panel',
alias : 'widget.leftpage',
title: "Left Page",
layout: null,
layoutConfig: null,
store: null,
attentive: true,
initComponent: function() {
var me = this;
// begin edit
// only set the store if is is not already defined
me.store = me.store ? me.store : Ext.StoreMgr.lookup('Sections'); // you may change this to any storename you want
// end edit
me.layout = { // don't set objects directly in class definitions
type: 'accordion',
align: 'stretch'
};
me.layoutConfig = { // dont set objects directly in class definitions
titleCollapse: true,
animate: true,
activeOnTop: true
};
me.callParent(arguments);
if (me.attentive) {
me.store('load', me.onRebuildContent, me);
if (me.store.count() == 0)
me.store.load();
} else {
me.buildContent();
}
},
buildContent: function() {
var me = this;
function addItem(rec) {
me.add({
xtype: 'panel',
title: rec.get('titleProperty'),
html: rec.get('bodyProprty')
});
};
me.store.each(addItem);
},
onRebuildContent: function() {
var me = this;
me.removeAll();
me.buildContent();
}
});
Your store will need at least two properties; one for the title and one for the content. And the store need to be loaded before you should instantiate this. But that can easily be done within your controller.
Edit based on comment and new OP info:
Well your view is a bit out of control of the controller. So I recommend you to simply use the StoreManager to receive a valid instance (I've edited the code, I just didn'T know the correct store to use). The StoreManager will know about the store as long as you list him within a controller (StoreManager is capable of much more, but that is all you need to know at the moment). For a further release you could also use the mixin bindable which would manage a storebinding more clean and enables you to update your accordion after the store receives new data (get updated)
Edit for readability
I've just cleaned it up a bit and included a switch param attentive which would allow you to use this component as directly bound to a store, reacting on all load events or as a sort of static one where the store should already be loaded. All in all this should give you a start without making it to complex.

How to read inline data written in a store from a controller in Sencha Touch 2.0 mvc

I am learning about Sencha so i have very basilar question.
I am trying to build a simple mvc application, with controller, views model and store.
I have this nmodel
Ext.define('rpc.model.Studenti', {
Extend: 'Ext.data.Model',
fields: [
{ name: 'cognome', type: 'string' },
{ name: 'previsione', type: 'string' }
]
});
this store (with inline data)
Ext.define('rpc.store.Studenti', {
model: 'rpc.model.Studenti',
storeId: 'gruppoStore',
autoLoad: true,
data: [
{cognome: 'uno', previsione: 'aaa'},
{cognome: 'due', previsione: 'bbb'},
{cognome: 'tre', previsione: 'ccc'}
]
});
the controller
Ext.define('rpc.controller.Home', {
extend: 'Ext.app.Controller',
stores: ['Studenti'],
models: ['Studenti'],
views: ['home.Fila','home.Griglia','home.Previsio'],
store: 'gruppoStore',
init: function() {
this.control({
'griglia button': {
tap: this.faqualcosa
}
});
},
faqualcosa: function(button){
...
var gruppoStoreMgr=this.getStudentiStore();
alert (gruppoStoreMgr.count());
for (var key in gruppoStoreMgr) {
//alert (key);
}
alert (gruppoStoreMgr.storeId);
alert (gruppoStoreMgr.isInstance);
//alert (gruppoStoreMgr.data);
alert (gruppoStoreMgr.autoLoad);
for (var key in gruppoStoreMgr.data[0]) {
//alert ("0"+key);
}
for (var key in gruppoStoreMgr.data[1]) {
//alert ("1"+key);
}
}
});
Please, what is the right way to access in function faqualcosa to the store data?
I've been able to have something like an instance (sure it is very near...) of the model with var gruppoStoreMgr=this.getStudentiStore(); but i have no trace of the data i've written in the store ("uno", "due"....). How to get that data? How to have in a controller funcion an object who refers to the real data in the store?
this.getStudentiStore().data.items
That is the most direct way to get to the data. It returns an array of the model records. If that's what you're looking for.
for(var i = 0; i < this.geStudentiStore().getCount(); i++ ) {
var record = this.getStudentiStore().getAt(i)
console.log(record.get('cognome'));
}
That should print out all the "cognomes"

Resources