I am having some difficulty with XTemplates and using the MVC structure. I have went through a few of the tutorials and by themselves they make sense but when I try to apply them to what I am trying to accomplish it does not work that well.
First off, my app consists of TabBarMVC and several views. Some of the views will have 'sub views'. I have the app working from a 'layout' perspective. Tabs are tabbing and views can access subviews. Now the issue is sending data to subviews.
An example is my Bill page to Detail page. In the bill page a user can enter a total and number of people to split the bill against. My controller takes both parameters and divides them and stores them in a 'guests' object. My guests object will be an array of 1-x number of guest objects. (based on the number to split).
I then send that object to an update method in my sub view to update a XTemplate but that is not happening. I can alert the object, and view the data in debugger but I do not know how to update the Xtemplate.
Here is the controller code:
splitdetail: function(options)
{
if ( ! this.splitdetailView)
{
var totalBill = options.data['totalBill'];
var numGuests = options.data['splitBy'];
var totalPerGuest = totalBill / numGuests;
var guestObject = new Array();
var theGuest;
for (var i=0; i<numGuests; i++) {
theGuest = {amount: totalPerGuest}
guestObject.push(theGuest);
}
app.views.calculatorSplitDetail.updateWithRecord(guestObject);
this.splitdetailView = this.render({
xtype: 'CalculatorSplitDetail',
switchAnimation: { type: 'slide'}
});
}
this.application.viewport.setActiveItem(this.splitdetailView, 'slide');
},
and here is my split detail
var guestTemplate = new Ext.XTemplate(
'<tpl for=".">',
'<div class=" x-field guest-amount-row x-field-number x-label-align-left">',
'<div class="x-form-label" style="width: 30%; ">',
'<span>Total bill</span>',
'</div>',
'<div class="x-form-field-container">',
'<input type="number" name="totalGuestAmount" class="x-input-number" value="{amount}">',
'</div>',
'</div>',
'</tpl>'
);
app.views.CalculatorSplitDetail = Ext.extend(Ext.form.FormPanel, {
initComponent: function() {
Ext.apply(this, {
scroll: false,
items: [
guestTemplate,
]
});
app.views.CalculatorSplitDetail.superclass.initComponent.call(this);
},
styleHtmlContent: true,
baseCls: 'calculator-splitdetail-panel',
updateWithRecord: function(record) {
guestTemplate.apply(record);
alert(record[0].amount);
}
});
Ext.reg('CalculatorSplitDetail', app.views.CalculatorSplitDetail);
guestTemplate is just a template, not a control, so it can't refresh itself, but it can generate new html for you. So all you need to do is update your panel with newly generated html:
updateWithRecord: function(record) {
this.update(guestTemplate.apply(record));
alert(record[0].amount);
}
Related
I have a simple List inside a container that I would like to see refreshed with new items when it is activated.
In my controller, I have an event for this:
onActivate: function() {
var that = this;
var store = this.getApprovalRequestsStore();
store.getProxy().setUrl('http://mobile-approvals-services.example.com/'+ Global.approvalsListUri + Approvals.app.user);
store.load({
callback: function (records, model) {
debugger;
that.getApprovalsList().refresh();
}
});
},
And in my list, I have a tpl for the items that come back from the store (verified I have items coming back from store at break point above), yet no items are shown:
Ext.define('Approvals.view.approvals.List', {
extend: 'Ext.List',
xtype: 'approvalsList',
config: {
itemId: 'ApprovalsList',
store: 'ApprovalRequests',
itemHeight: 70,
variableHeights: false,
pressedDelay: 0,
emptyText: "<div>No Approvals Found</div>",
loadingText: "Loading...",
onItemDisclosure: false,
itemTpl: '<div class="listView">Request For: {requestedFor}</div>',...
Is there something flawed in my approach?
It was a problem with the reader. Once I set totalProperty and successProperty to values being returned from the service it worked. WTHO.
On the front-end I have a Calls grid. Each Call may have one or more Notes associated with it, so I want to add the ability to drill down into each Calls grid row and display related Notes.
On the back-end I am using Ruby on Rails, and the Calls controller returns a Calls json recordset, with nested Notes in each row. This is done using to_json(:include => blah), in case you're wondering.
So the question is: how do I add a sub-grid (or just a div) that gets displayed when a user double-clicks or expands a row in the parent grid? How do I bind nested Notes data to it?
I found some answers out there that got me part of the way where I needed to go. Thanks to those who helped me take it from there.
I'll jump straight into posting code, without much explanation. Just keep in mind that my json recordset has nested Notes records. On the client it means that each Calls record has a nested notesStore, which contains the related Notes. Also, I'm only displaying one Notes column - content - for simplicity.
Ext.define('MyApp.view.calls.Grid', {
alias: 'widget.callsgrid',
extend: 'Ext.grid.Panel',
...
initComponent: function(){
var me = this;
...
var config = {
...
listeners: {
afterrender: function (grid) {
me.getView().on('expandbody',
function (rowNode, record, expandbody) {
var targetId = 'CallsGridRow-' + record.get('id');
if (Ext.getCmp(targetId + "_grid") == null) {
var notesGrid = Ext.create('Ext.grid.Panel', {
forceFit: true,
renderTo: targetId,
id: targetId + "_grid",
store: record.notesStore,
columns: [
{ text: 'Note', dataIndex: 'content', flex: 0 }
]
});
rowNode.grid = notesGrid;
notesGrid.getEl().swallowEvent(['mouseover', 'mousedown', 'click', 'dblclick', 'onRowFocus']);
notesGrid.fireEvent("bind", notesGrid, { id: record.get('id') });
}
});
}
},
...
};
Ext.apply(me, Ext.apply(me.initialConfig, config));
me.callParent(arguments);
},
plugins: [{
ptype: 'rowexpander',
pluginId: 'abc',
rowBodyTpl: [
'<div id="CallsGridRow-{id}" ></div>'
]
}]
});
I've a store and model to make AJAX Call and get the result.
Here is my View
Ext.define('kids.view.YouTube', {
extend: 'Ext.Component',
alias: 'widget.YouTubePlayer',
xtype: 'YouTube',
config: {
url: 'http://www.youtube.com/embed/',
videoId: 'qsvpvqvApKo',
vWidth: 420,
vHeight: '315',
styleHtmlContent: true,
aaa: '1',
},
initialize: function() {
var prod = Ext.create('kids.store.vids');
prod.load(function ( ){
prod.each(function (record, id){
tmp = tmp + record.get('vid_url');
});
});
this.callParent(arguments);
var out = Ext.String.format(
[
'<div align="center">',
'<iframe width="{0}" height="{1}" src="{2}"',
'frameborder="0" allowfullscreen></iframe>',
'</div>'
].join(''),
this.getVWidth(),
this.getVHeight(),
**tmp //(the dynamic variable i formed in onLoad event of store**
);
console.log(tmp);
this.setHtml(out);
}
});
I used prod=ext.create('kids.store.vids');
and i'm using onload function, which is fetching values correctly.
how can i use tmp variable out side of onload, becuase the variable is becoming empty. and inside the store.load(function) i can not use this.callParent()
h*ow can i pass dynamic html here, as per the store returned values?*
help me
Pavan
Got it thanks
i've used panel.setHtml to update the html from the variable which i got from store.
thanks
I have a vbox layout for my parent container and have 3 items, one with static data and two other lists. I would like my lists' heights expand to 100% of the size of the content inside of them and I have an example of this here.
As you can see, this works great when you have the data right there and ready to serve up, but in my case, I need to fetch the data for the two lists in the callback and set the respective store for each list. The problem is if I don't specify a height, the lists will be collapsed and will show no list data. I've tried 'fit' and to refresh() the view in the callback but nothing seems to work. Any ideas?
This is my method in the controller to fill the stores:
function buildOrgView (record, view) {
var managerUid = record.get('managerUid');
var uid = record.get('uid');
//Get data for org view
if (managerUid) {
var managerStore = new People.store.EmployeeDetails();//Ext.data.StoreManager.lookup('mgrDetailsStore');
managerStore.getProxy().setUrl(People.app.userDetailsUrl + managerUid);
managerStore.load({
callback: function (records) {
var peerStore = new People.store.OrgMembers();
peerStore.getProxy().setUrl(People.app.orgMembersUrl + managerUid);
peerStore.load({
callback: function (recs) {
Ext.each(recs, function(item, idx, allItems) {
if (item.get('fullName') == record.get('fullName')) {
peerStore.remove(item);
}
});
view.getPeersList().setStore(peerStore);
var drStore = new People.store.OrgMembers();
drStore.getProxy().setUrl(People.app.orgMembersUrl + uid);
drStore.load({
callback: function (recs) {
view.getDirectReportsList().setStore(drStore);
}
});
}
});
}
});
}
}
This is the List component I'd like to populate:
Ext.define('People.view.people.OrgList', {
extend: 'Ext.List',
xtype: 'orgList',
config: {
cls: 'peopleInfo',
store: 'OrgMembers',
// scrollable: true,
// height: 300,
itemTpl: [
"<div class='listView small'>",
" <tpl if='workforceID != undefined'>",
" <tpl if='workforceID == \"phind\"'>",
" <div class='avatar notFound user'></div>",
" <tpl else>",
" <div class='avatar'></div>",
" </tpl>",
" </tpl>",
" <ul class='data'>",
" <li><h3>{fullName}</h3></li>",
" </ul>",
"</div>"
],
listeners: [
{
fn: 'onPersonTap',
event: 'itemtap'
}
]
},
onPersonTap: function (dataview, newValue, oldValue, eOpts) {
debugger;
this.fireEvent('persontap', this, newValue, oldValue, eOpts);
}
});
The best way I found to resolve this issue was to multiple the number of elements in the list by the height of each element as I have defined in config and then add the height of the header (in my case 27px). That yields the desired effect although, it's a bit hacky (fit layout should've really worked).
view.getPeersList().setHeight(recs.length*50 + 27);
I was able to fix the heights of the items using these two params in Sencha Touch 2.1.1:
itemHeight: 50,
variableHeights: false,
You can set min height of list after setting store like this:
list.setMinHeight(Ext.Viewport.getWindowHeight()/2);
or you can do this in initialize function of list view.
I have a list of items and I have inserted toggle button in my list. Now depending on the value of active in the store I am trying to set the value of toggle button.
The problem I am facing is I don't know how to get list's record without tapping or selecting it.
Here is the code ..
var itemTemplate = new Ext.XTemplate (
'<tpl for = ".">',
'<div>{name}</div>',
'<div class= "subSectionToggleButton"></div>',
'</tpl>'
);
var subSectionList = {
height: 350,
id: 'sList',
xtype: 'list',
store: App.stores.subSections,
grouped: true,
itemTpl: itemTemplate, //Don't need to worry about this
listeners: {
'refresh' : function (e) {
//insert toggle button in empty div class inside template
e.getEl().select('div .subSectionToggleButton').each(function(item) {
var toggleButton = new Ext.form.Toggle ({
renderTo: item,
listeners : {
// After render I want to get the individual record, read whether it is active or not.. and then do setValue(value) on toggle button
'afterrender' : function (f) {
var rec = Ext.getCmp('sList').getRecord(f);
console.log(rec); // I get undefined here
// I know how to get a record when you tap a list item but how do I get without using the tap.
}
}
});
});
}
}
};
It will be best for you to use an if condition in your itemTpl or just get the value decided from a function. So, it will be like this:
var itemTpl = new Ext.XTemplate('<tpl for = ".">',
'<div>{name}</div>',
'<div class= "subSectionToggleButton">{active:this.setToggled}</div>',
'</tpl>',
setToggled : function(active){
if(active == true){ //Check the condition here
return '<div class="active">Active</div>';
}
return '<div class="inactive">Inctive</div>';
}
Or, you can just use a tpl if condition like this:
var itemTpl = new Ext.XTemplate('<tpl for = ".">',
'<div>{name}</div>',
'<tpl if="active==true">', // Or '<tpl if="active==\'true\'">',
'<div class= "subSectionToggleButton">Active</div>',
'</tpl>',
'<tpl if="active==false">',
'<div class= "subSectionToggleButton">Inactive</div>',
'</tpl>',
'</tpl>');
For your given scenario try to pass HTMLElement instead of Ext.Element to getRecord method
var rec = Ext.getCmp('sList').getRecord(f.getEl().dom);
Also you can get access to the list's records through list.store.findRecord
http://docs.sencha.com/touch/1-1/source/Store.html#Ext-data-Store-method-findRecord