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 :)
Related
I have a problem with DataTables - I want to use the responsive add-on to hide columns on smaller screen sizes, unfortunately the responsive add-on is hiding columns on larger screen sizes when it really doesn't need to.
Here is my javascript code:
var table = $('#peopleTable').DataTable({
responsive: true,
ajax: {
dataType: 'text',
type: 'POST',
url: apiUrl,
dataSrc: function (json) {
return $.parseJSON(json);
}
},
columns: [
{
data: 'name',
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
return '<img class="icon" title="' + row.people_type + '" src="<?php echo $localPath; ?>/webimg/people-type/b/' + row.people_type_id + '.png">' + row.main_contact + ' # ' + row.name + '';
}
},
/*{
data: 'main_contact',
responsivePriority: 1,
width: '5%'
},*/
{
data: 'add1',
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
var output = [];
if (row.add1) { output.push(row.add1); }
if (row.add2) { output.push(row.add2); }
if (row.add3) { output.push(row.add3); }
if (row.town) { output.push(row.town); }
var outputStr = output.join(', ');
return '<span class="address-trunc" title="' + outputStr + '">' + outputStr + '</span>';
}
},
{
data: 'phone',
responsivePriority: 1,
width: '5%'
},
/*{
data: 'email',
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
return '' + row.email + '';
}
},*/
{
data: 'id',
orderable: false,
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
var url = '<?php echo $localPath;?>/people/person.php?id=' + row.id;
return 'View '
<?php if ($activeUser->can('delete')) { ?>
+ 'Delete'
<?php } ?>
;
}
}
]
});
As you can see I have been playing about with the code in order to make all the columns appear on a large screen size.
When I started off I had more columns in play (they are now commented out), I had all the widths adding up to 100%, and I have all the responsivePrioritys set to correct values (instead of them all being 1).
Reducing the number of columns, setting lower widths, altering responsivePrioritys - doing all of these things had no effect, on a large screen the responsive add-on was still insisting on hiding at least 1 column.
How do I stop this? I still want to use the add-on as it is very useful on smaller screens, but I don't want it force the hiding of columns when it doesn't need to.
To show you what is happening, here is a screen shot - you can see the huge almost-empty columns where there is plenty of room for another column - and yet DataTables is insisting on hiding a column behind the + symbol on the far left.
Responsive extension has many classes to configure when columns should be visible/hidden.
You could use desktop class to specify columns shown for window width greater than or equal to 1024 px.
See this example for code and demonstration.
Why not just use
var table = $('#peopleTable').DataTable({
responsive: window.innerWidth < 1000 ? true : false,
...
})
I mean simply not initialize the responsive extension when it is not needed. 1000 is just a suggestion, "larger screen sizes" is relative :)
demo -> http://jsfiddle.net/8vtqsf7z/
Ok, so I would like to have a slider that looks like this one.
Just can't figure out where we can at least have these delimiter separators? So if you see there are 7 delimiters and we have large labels on the first 4-th and the last delimeter.
How would you approach this task?
This is a rather old question but I was faced with the very same need today. Building on GenieWanted's answer, I came to this:
...
{
xtype: 'sliderfield',
maxValue: 5,
label: 'Some data',
html: '<table width="100%" align="left"><tr><td width="25%">Min</td><td width="50%" align="center">Med</td><td width="25%" align="right">Max</td></tr></table>'
}
...
which works very well for me, and avoids messing around to find the correct number of needed. Also, I suspect that results would vary from device to device using .
There is no way of adding a label inside sliderfield. However, you can indeed add HTML to acheive the required output. On the config panel, go to HTML property, and add something like this:
<div style="padding-left:1em">| | |<div>Low Average High </div></div>
The output I have got:
You just need to playaround with the alignment of your text in the HTML. That will do!
Good Luck!
You can create Custom Slider like this
Ext.ns('Ext.ux');
Ext.ux.CustomSlider = Ext.extend(Object, {
valueTextClass: 'x-slider-value-text',
showSliderBothEndValue: true,
sliderEndValueStyle: 'color: black',
constructor: function(config){
Ext.apply(this, config);
Ext.ux.CustomSlider.superclass.constructor.apply(this, arguments);
},
init: function(parent) {
var me = this;
parent.on({
painted: {
fn: function(component) {
if (me.showSliderBothEndValue) me.showSliderEndValue(this);
if (!this.valueTextEl) {
this.valueTextEl = component.element.createChild({
cls: me.valueTextClass
});
}
}
}
});
},
showSliderEndValue: function(slider) {
var sliderPosX = slider.getComponent().getThumb().element.getX();
var thumbHeight = slider.getComponent().getThumb().element.getHeight();
var sliderLength = slider.getComponent().element.getWidth();
var minValueEl = slider.getComponent().element.createChild();
minValueEl.setHtml(slider.getComponent().getMinValue());
minValueEl.applyStyles('overflow:hidden;position:absolute');
minValueEl.applyStyles(this.sliderEndValueStyle);
minValueEl.setLeft(14);
minValueEl.setTop(thumbHeight -7);
var maxValueEl = slider.getComponent().element.createChild();
maxValueEl.setHtml(slider.getComponent().getMaxValue());
maxValueEl.applyStyles('overflow:hidden;position:absolute');
maxValueEl.applyStyles(this.sliderEndValueStyle);
maxValueEl.setLeft(sliderLength-45);
maxValueEl.setTop(thumbHeight - 7);
}
});
And create slider like this
var slider = {
xtype: 'sliderfield',
flex : 6,
label: "Percentage",
name: "Percentage",
value : 50,
minValue : 0,
maxValue : 100,
labelWrap : true,
labelAlign : 'left',
increment : 10,
plugins: [new Ext.ux.CustomSlider({
showSliderBothEndValue: true
})],
listeners: {
painted: function (slider) {
var sliderPanelItems = this.parent.getInnerItems();
sliderPanelItems[1].setValue(this.getValue());
},
change: function (me,slider, thumb, newVal, oldVal, opts) {
var sliderPanelItems = this.parent.getInnerItems();
sliderPanelItems[1].setValue(newVal);
}
}
};
Result will be like this
I did this using this link
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 want to display data that i receive from a data store. One way that i have tried, is to take a text field make it disabled and then set its value with store data.
But i don't think it is the correct solution so i am trying to use label instead and I am not getting how it can be done. Can you guys can point me to correct way of doing it.? Any help appreciated .
Thanks,
Mehul Makwana.
This post is a little old but I was research the for same topic and ended up using a different approach.
I'm using Sencha Touch v2.0. I create the label and place it inside the form.Panel as one would normally do. I then configured the label tpl in designer to include the model fields. When applying the values to the formpanel, I also invoke the apply() method on the label tpl. The following working sample illustrate it.
app.js:
Ext.Loader.setConfig({
enabled: true
});
Ext.application({
views: [
'MyFormPanel'
],
name: 'MyApp',
launch: function() {
Ext.create('MyApp.view.MyFormPanel', {fullscreen: true});
}
});
view.MyFormPanel.js
Ext.define('MyApp.view.MyFormPanel', {
extend: 'Ext.form.Panel',
alias: 'widget.myformpanel',
config: {
items: [
{
xtype: 'label',
itemId: 'myLabel',
tpl: [
'Hello, {firstName} {lastName}, please change your email below:',
''
]
},
{
xtype: 'textfield',
label: 'Email:'
}
],
listeners: [
{
fn: 'onFormpanelInitialize',
event: 'initialize'
}
]
},
onFormpanelInitialize: function(component, options) {
var person = Ext.decode("{firstName: 'John',lastName: 'Dow',email: 'jd#somewhere.com'}");
// apply value to the form
this.setValues(person);
// get the updated text for the label
var label = this.down('#myLabel');
var html = label.getTpl().apply(person);
label.setHtml(html);
}
});
So the idea is save the label template in the label.tpl field, then get the runtime label value using apply() method of Template, then set the label text to it.
I recently tried to solve this problem by creating a 'label' form component. I posted about it in a blog article I wrote on Sencha/PhoneGap. Here is the code:
Ext.form.LabelField = function(config){
Ext.form.LabelField.superclass.constructor.call(this, config);
};
Ext.extend(Ext.form.LabelField, Ext.form.Field, {
isField: true,
value: '',
renderSelectors: {fieldEl: '.x-form-labelfield'},
renderTpl: [
'<tpl if="label">',
'<div class="x-form-label"><span>{label}</span></div>',
'</tpl>',
'<div class="x-form-label x-form-labelfield" style="width:70%; text-align:right"><span>{value}</span></div>',
],
setValue:function(val) {
this.value = val;
if(this.rendered){
this.fieldEl.update('<span>' + val + '</span>');
}
return this;
},
});
Ext.reg('labelfield', Ext.form.LabelField);
Let me know if this does the trick.
Thank you mistagrooves. That was exactly what I was looking for. I reccomand removing x-form-label class and using these styles:
.x-form-labelfield {
-webkit-box-flex: 1;
box-flex: 1;
width: 100%;
position: relative;
-webkit-border-radius: 0;
border-radius: 0;
padding: .4em;
border: 0;
min-height: 2.5em;
display: block;
background: white none;
-webkit-appearance: none;
}