In my combobox i have something like this:
displayTpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'{Nome} ({Valor})',
'</tpl>')
It works fine except that if there isn't a pre-selected value for the combo, it shows this "()"
So i've tried to create a template that when the value is empty then it show nothing like this:
displayTpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<tpl if="this.isEmpty({Nome})">',
'',
'<tpl else>',
'{Nome} ({Valor})',
'</tpl>',
'</tpl>',
{
isEmpty: function (value) {
return value == '';
}
})
But i keep getting a error message "Expected :" when the tpl is evaluated (extjs-all-debug)
compile: function (tpl) {
var me = this,
code = me.generate(tpl);
return me.useEval ? me.evalTpl(code) : (new Function('Ext', code))(Ext);
Any ideas on how to do this?
You don't need the { } for the expression in the tpl tag. So try this template instead:
'<tpl for=".">',
'<tpl if="this.isEmpty(Nome)">',
'',
'<tpl else>',
'{Nome} ({Valor})',
'</tpl>',
'</tpl>'
I've solve it :)
displayTpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<tpl if="Nome != \'\'">',
'{Nome} ({Valor})',
'<tpl else>',
'',
'</tpl>',
'</tpl>'
)
Since i can't seem to understand what value is being passed to the combo i figure if it's different from empty then return the structure i want, if not then return ''
Related
I'm trying to make an input with auto-completion but since I 'm working with emoticons need to show a picture and text on the list of recommendations
<div id="demo" class="yui3-skin-sam">
<input id="ac-input" type="text">
</div>
YUI().use('autocomplete', 'autocomplete-filters', 'autocomplete-highlighters', function (Y) {
Y.one('#ac-input').plug(Y.Plugin.AutoComplete, {
resultFilters : 'phraseMatch',
resultHighlighter: 'phraseMatch',
source : ['Alabama','Alaska','Arizona']
});
});
The output should be something like
thanks !!!
Here is a great example right from the YUI3 Documentation:
http://yuilibrary.com/yui/docs/autocomplete/ac-flickr.html?mock=true
The most important part of this code is the result formatter:
resultFormatter: function (query, results) {
return Y.Array.map(results, function (result) {
return '<div class="result">' +
'<img class="photo" src="' + getImageUrl(result) + '" alt="thumbnail">' +
'<span class="title">' + result.highlighted + '</span>' +
'</div>';
});
}
Haven't done something like that with icons etc. but I would check result formatter first and if it is not "good enough" I would try extending AutoCompleteBase. Example from YUI site:
// HTML template string that will be used for each tweet result.
var tweetTemplate =
'<div class="tweet">' +
'<div class="hd">' +
'<img src="{profile_image_url}" class="photo" ' +
'alt="Profile photo for {from_user}">' +
'</div>' +
'<div class="bd">' +
'<strong class="user">{from_user}</strong>' +
'<span class="tweet-text">{highlighted}</span>' +
'</div>' +
'<div class="ft">{created_at}</div>' +
'</div>';
// Custom formatter for tweets.
function tweetFormatter(query, results) {
// Iterate over the array of tweet result objects and return an
// array of HTML strings.
return Y.Array.map(results, function (result) {
var tweet = result.raw;
// Use string substitution to fill out the tweet template and
// return an HTML string for this result.
return Y.Lang.sub(tweetTemplate, {
created_at : tweet.created_at,
from_user : tweet.from_user,
highlighted : result.highlighted,
profile_image_url: tweet.profile_image_url
});
});
}
// Instantiate AutoComplete using the custom formatter.
Y.one('#ac-input').plug(Y.Plugin.AutoComplete, {
resultFormatter: tweetFormatter,
resultHighlighter: 'phraseMatch',
resultListLocator: 'results',
resultTextLocator: 'text',
source: 'http://search.twitter.com/search.json?q={query}&callback={callback}'
});
Both will take quite a lot of reading and experimenting, but you should be able to modify it to suit your needs...
Is it possible to merge 2 columns in TreeGrid, when one of them is xtype 'treecolumn'?
For now I have 2 separate columns, one is standard treecolumn, second is templatecolumn with custom template (basically an image)
What I would like to get should look like this:
So that second column content is added to first but aligned to right.
I have no idea how to even start with that kind of renderer :(
This is code for my columns so far:
{
xtype : 'treecolumn',
text : 'DziaĆ/Pracownik',
width : 200,
sortable : true,
hideable: false,
dataIndex : 'Name',
renderer: function (v, m, r) {
if(r.get('leaf')==true)
m.tdAttr = 'data-qtip="<img src=services/Images.ashx?login='+r.get('login')+' width=60px height=60px>"';
return v;
}
},
{
text : 'Zdj',
width: 40,
align : 'center',
dataIndex : 'Name',
sortable : false,
resizable: false,
xtype : 'templatecolumn',
tpl : imgTpl
},
...
var imgTpl = Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<tpl if="values.leaf == true">',
'<img src="services/Images.ashx?login={login}" width="25px" height="25px"/>',
'</tpl>',
'</tpl>'
);
I will really be gratefully for any hints on how to merge those 2 columns.
Here is what I ended up doing with that:
renderer:function (value, meta, record) {
var tasks = record.get("tasks"),
tpl = this.taskImgTpl,
type, qtip;
if (tasks && tasks.length >0){
Ext.each(tasks, function(task){
if(task.refType) {
type = task.refType;
} else {
type = task.type.name;
}
qtip = Ext.String.format('Status: {0} Assignee: {1} %Complete: {2}',task.state,task.assignee||'',task.pctComplete);
value += tpl.apply([type, qtip]);
},this);
}
return value;
}
And the image template that is being inserted is :
taskImgTpl:new Ext.XTemplate(" <img class='{0} h16' width='16px' data-qtitle='{0}' data-qwidth='120' data-qtip='{1}'/>")
where h16 is a class that gives height:16px, and the dynamically inserted class carries a background image (16x16) of whatever the type of object is being displayed. You of course can just set the src attribute instead.
What I have done is instead using template I've used renderer, so my column now looks like this:
{
xtype : 'treecolumn',
text : 'Employee',
width : 200,
sortable : true,
hideable : false,
dataIndex : 'Name',
renderer : function(v, m, r) {
if (r.get('leaf')) {
return '<div style="float: left">'
+ r.get('Name')
+ '</div><img data-qtip="<img src=services/Images.ashx?login='
+ r.get('login')
+ ' width=60px height=60px/>" src="services/Images.ashx?login='
+ r.get('login')
+ '" width="25px" height="25px" style="float: right; margin-right: 5px"/>';
}
return '<div style="float: left">' + r.get('Name') + '</div>';
}
}
If element is leaf then I display extra image in the right of my column + I've added bigger image after rollover.
To have this working I had to change some css inside ext-all.css:
.x-grid-with-row-lines .x-tree-icon{margin-top:1px; float: left}
.x-grid-with-row-lines .x-tree-elbow,.x-grid-with-row-lines .x-tree-elbow-end,.x-grid-with-row-lines .x-tree-elbow-plus,.x-grid-with-row-lines .x-tree-elbow-end-plus,.x-grid-with-row-lines .x-tree-elbow-empty,.x-grid-with-row-lines .x-tree-elbow-line{height:19px;background-position:0 -1px; float: left}
I had to add float:left to all images that are displayed in that cell:
x-tree-elbow
x-tree-elbow-end
x-tree-elbow-plus
x-tree-icon
I know that this can be optimised a lot, but for me it works fine. If some ExtJS guru could tweak it to work better then you're welcome :)
I'm trying to create a condition inside a tooltip template.
I've declared my template like this:
tooltipTpl: new Ext.XTemplate(
'<tpl for=".">',
'<dl class="eventTip">',
'<tpl if="values.getLength() == 1">',
'<dt class="icon-clock">Time</dt><dd>{[Ext.Date.format(values.start, "d-m")]} - {[Ext.Date.format(Ext.Date.add(values.end,Ext.Date.SECOND,-1), "d-m")]}</dd>',
'</tpl>',
'<tpl if="values.getLength() > 1">',
'<dt class="icon-clock">Day</dt><dd>{[Ext.Date.format(values.start, "d-m")]}</dd>',
'</tpl>',
'<dt class="icon-task">Status</dt><dd>{Name}</dd>',
'</dl>',
'</tpl>'
).compile(),
The idea behind is to be able to display 2 dates (start and end) if event is longer than 1 day, if it is one day event just display that date.
I've declared my model as so:
Ext.define('Urlopy.Model.Plan', {
extend : 'Sch.model.Event',
idProperty : 'id',
resourceIdField : 'userID',
startDateField : 'start',
endDateField : 'end',
fields : [{ name : 'id', type : 'int'},
{ name : 'userID', type : 'string'},
{ name : 'start', type : 'date', dateFormat : 'MS'},
{ name : 'end', type : 'date', dateFormat : 'MS'},
{ name : 'Name'}],
getLength : function() {
return Sch.util.Date.getDurationInDays(this.get('start'), this.get('end'));
}
});
The second line of my tooltip is displayed, but line with dates isn't. It looks like I cant call function from my model in my template.
How to fix this? Is it possible?
The answer to the question - if it is possible to run function from the object passed to the template as a data object, yes. The function will be called.
You can run the following short snippet of code inside the any browser console like FireBug
(of course you need to open the console at the page which has extjs, simple open console on the extjs documentation page) to see it.
Code snippet:
var t = new Ext.XTemplate(
'<tpl for=".">',
'\n===',
'<tpl if="values.getLength() == 1"> ONE </tpl>',
'<tpl if="values.getLength() > 1"> TWO </tpl>',
' *{name}* ',
'===',
'</tpl>'
).compile();
var a = [
{name: 'Foo', getLength: function() {return 1;} },
{name: 'Boo'}
];
var s = t.apply(a);
console.log(s);
You will see the following results:
return 1:
=== ONE *Foo* ===
=== *Boo* ===
return > 1:
=== TWO *Foo* ===
=== *Boo* ===
I don't know the context of using this template with the underlying model, you are not provided code applying the model to the template. But I'm pretty sure that to the template is going the model data but not the whole model object, that is why you can see the second line with modal's field {Name}.
To overcome it you can add to the template its own method, like:
//for the simplicity sake I've not pasted the whole template
//also you can call the *this.getLength(values.start, values.end)*
//and change this method parameters
var tooltipTpl = new Ext.XTemplate(
'<tpl for=".">',
// ...
'<tpl if="this.getLength(values) > 1">',
// ...
'</tpl>',
// ...
'</tpl>'
,{
getLength : function(data) {
//move the model method to the template
return Sch.util.Date.getDurationInDays(data.start, data.end);
}
}).compile();
You can use the model's method..
Define the model static method:
Ext.define('Urlopy.Model.Plan', {
//...
static: {
getLength: function(data) {
console.log('data', data);
console.log(data.start, data.end);
return 5; //just test function
}
}
//.....
});
Use it in the template:
'<tpl if="Urlopy.Model.Plan.getLength(values) == 1">'
So you can delete the template's method.
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
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);
}