PDA

View Full Version : ComponentDataView - Ext components inside a dataview or listview



Condor
1 Sep 2009, 1:03 AM
DataView and ListView are very useful to render store based data as HTML. This extension adds the ability to include Ext components in the HTML without the need to keep track of them (e.g. you won't get a memory leak when you update or delete a record).
It also supports automatically getting and setting the value from the store if the component is an Ext.form.Field.

Ext.ux.ComponentDataView:

Ext.ns('Ext.ux');
Ext.ux.ComponentDataView = Ext.extend(Ext.DataView, {
defaultType: 'textfield',
initComponent : function(){
Ext.ux.ComponentDataView.superclass.initComponent.call(this);
this.components = [];
},
refresh : function(){
Ext.destroy(this.components);
this.components = [];
Ext.ux.ComponentDataView.superclass.refresh.call(this);
this.renderItems(0, this.store.getCount() - 1);
},
onUpdate : function(ds, record){
var index = ds.indexOf(record);
if(index > -1){
this.destroyItems(index);
}
Ext.ux.ComponentDataView.superclass.onUpdate.apply(this, arguments);
if(index > -1){
this.renderItems(index, index);
}
},
onAdd : function(ds, records, index){
var count = this.all.getCount();
Ext.ux.ComponentDataView.superclass.onAdd.apply(this, arguments);
if(count !== 0){
this.renderItems(index, index + records.length - 1);
}
},
onRemove : function(ds, record, index){
this.destroyItems(index);
Ext.ux.ComponentDataView.superclass.onRemove.apply(this, arguments);
},
onDestroy : function(){
Ext.ux.ComponentDataView.onDestroy.call(this);
Ext.destroy(this.components);
this.components = [];
},
renderItems : function(startIndex, endIndex){
var ns = this.all.elements;
var args = [startIndex, 0];
for(var i = startIndex; i <= endIndex; i++){
var r = args[args.length] = [];
for(var items = this.items, j = 0, len = items.length, c; j < len; j++){
c = items[j].render ?
c = items[j].cloneConfig() :
Ext.create(items[j], this.defaultType);
r[j] = c;
if(c.renderTarget){
c.render(Ext.DomQuery.selectNode(c.renderTarget, ns[i]));
}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, ns[i]));
}else{
c.render(ns[i]);
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}
}
}
this.components.splice.apply(this.components, args);
},
destroyItems : function(index){
Ext.destroy(this.components[index]);
this.components.splice(index, 1);
}
});
Ext.reg('compdataview', Ext.ux.ComponentDataView);
Ext.ux.ComponentListView:

Ext.ux.ComponentListView = Ext.extend(Ext.ListView, {
defaultType: 'textfield',
initComponent : function(){
Ext.ux.ComponentListView.superclass.initComponent.call(this);
this.components = [];
},
refresh : function(){
Ext.destroy(this.components);
this.components = [];
Ext.ux.ComponentListView.superclass.refresh.apply(this, arguments);
this.renderItems(0, this.store.getCount() - 1);
},
onUpdate : function(ds, record){
var index = ds.indexOf(record);
if(index > -1){
this.destroyItems(index);
}
Ext.ux.ComponentListView.superclass.onUpdate.apply(this, arguments);
if(index > -1){
this.renderItems(index, index);
}
},
onAdd : function(ds, records, index){
var count = this.all.getCount();
Ext.ux.ComponentListView.superclass.onAdd.apply(this, arguments);
if(count !== 0){
this.renderItems(index, index + records.length - 1);
}
},
onRemove : function(ds, record, index){
this.destroyItems(index);
Ext.ux.ComponentListView.superclass.onRemove.apply(this, arguments);
},
onDestroy : function(){
Ext.ux.ComponentDataView.onDestroy.call(this);
Ext.destroy(this.components);
this.components = [];
},
renderItems : function(startIndex, endIndex){
var ns = this.all.elements;
var args = [startIndex, 0];
for(var i = startIndex; i <= endIndex; i++){
var r = args[args.length] = [];
for(var columns = this.columns, j = 0, len = columns.length, c; j < len; j++){
var component = columns[j].component;
c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);
r[j] = c;
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
if(c.renderTarget){
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, node));
}else{
c.render(node);
}
if(c.applyValue === true){
c.applyValue = columns[j].dataIndex;
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}
}
}
this.components.splice.apply(this.components, args);
},
destroyItems : function(index){
Ext.destroy(this.components[index]);
this.components.splice(index, 1);
}
});
Ext.reg('complistview', Ext.ux.ComponentListView);

Usage example:

Ext.onReady(function() {
new Ext.Viewport({
layout: 'hbox',
layoutConfig: {
align: 'stretch'
},
defaults: {
flex: 1
},
items: [{
title: 'ComponentDataView example',
items: {
xtype: 'compdataview',
store: [[1, 'One'], [2, 'Two'], [3, 'Three']],
itemSelector: 'tbody tr',
tpl: '<table><thead><tr><td>Value</td><td>Text</td></tr></thead><tbody><tpl for="."><tr><td></td><td></td></tr></tpl></tbody></table>',
items: [{
xtype: 'numberfield',
minValue: 0,
maxValue: 100,
renderTarget: 'td:nth(1)',
applyValue: 'field1'
},{
allowBlank: false,
renderTarget: 'td:nth(2)',
applyValue: 'field2'
}]
}
},{
title: 'ComponentListView example',
items: {
xtype: 'complistview',
store: [[1, 'One'], [2, 'Two'], [3, 'Three']],
columns: [{
header: 'Value',
width: .5,
dataIndex: 'field1',
tpl: ' ',
component: {
xtype: 'numberfield',
minValue: 0,
maxValue: 100,
applyValue: true
}
},{
header: 'Text',
width: .5,
dataIndex: 'field2',
tpl: ' ',
component: {
allowBlank: false,
applyValue: true
}
}]
}
}]
});
});

jnicora
1 Sep 2009, 8:20 AM
very slick

d0uble_hel1x
1 Sep 2009, 8:45 AM
i was just looking for a solution like this! how do i renderTarget to div or input instead of tr?

also it would be nice if the form containing your extension can submit and load the folloing json:



{
first:'John',
last:'Doe',
company:'Some Company',
email:'email@abc.com',
phones:[{
phone:'11111111',type:'mobile'
},{
phone:'22222222',type:'office'
},{
phone:'33333333',type:'home'
}]
}



this is what i'm experimenting with:




<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Complex form test</title>

<link rel='stylesheet' type='text/css' href='http://extjs.com/deploy/dev/resources/css/ext-all.css'/>
<script type="text/javascript" src="http://extjs.com/deploy/dev/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://extjs.com/deploy/dev/ext-all-debug.js"></script>


</head>
<body>
</body>
</html>

<script language="javascript" type="text/javascript">
Ext.QuickTips.init();
</script>

<script type="text/javascript" language="javascript">

Ext.ns('Ext.ux.form');

//MyForm=Ext.extend(Ext.form.FormPanel,{
MyForm=Ext.extend(Ext.Panel,{

initComponent:function(){

Ext.apply(this,{
//baseCls: 'x-plain',
labelWidth: 55,
//url:'save-form.php',
defaultType: 'textfield',
layout:'hbox',
items: [{
fieldLabel: 'Phone',
name: 'phone',
anchor:'100%', // anchor width by percentage
xtype:'textfield'
},{
fieldLabel: 'Type',
name: 'type',
anchor: '100%' // anchor width by percentage
}]

})

MyForm.superclass.initComponent.call(this)
},

initFields : function(){
//var f = this.form;
var formPanel = this;
var fn = function(c){
if(formPanel.isField(c)){
//f.add(c);
}if(c.isFieldWrap){
Ext.applyIf(c, {
labelAlign: c.ownerCt.labelAlign,
labelWidth: c.ownerCt.labelWidth,
itemCls: c.ownerCt.itemCls
});
//f.add(c.field);
}else if(c.doLayout && c != formPanel){
Ext.applyIf(c, {
labelAlign: c.ownerCt.labelAlign,
labelWidth: c.ownerCt.labelWidth,
itemCls: c.ownerCt.itemCls
});
if(c.items){
c.items.each(fn, this);
}
}
};
this.items.each(fn, this);
},

onRender : function(ct, position){
this.initFields();
Ext.FormPanel.superclass.onRender.call(this, ct, position);
//this.form.initEl(this.body);
},
isField : function(c) {
return !!c.setValue && !!c.getValue && !!c.markInvalid && !!c.clearInvalid;
},

setValues : function(values){
if(Ext.isArray(values)){ // array of objects
for(var i = 0, len = values.length; i < len; i++){
var v = values[i];
var f = this.findField(v.id);
if(f){
f.setValue(v.value);
if(this.trackResetOnLoad){
f.originalValue = f.getValue();
}
}
}
}else{ // object hash
var field, id;
for(id in values){
if(!Ext.isFunction(values[id]) && (field = this.findField(id))){
field.setValue(values[id]);
if(this.trackResetOnLoad){
field.originalValue = field.getValue();
}
}
}
}
return this;
},

findField : function(id){
var field = this.items.get(id);
if(!Ext.isObject(field)){
this.items.each(function(f){
if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
field = f;
return false;
}
});
}
return field || null;
}


})

Ext.ux.form.ArrayField = Ext.extend(Ext.form.Field,{

onRender : function(ct, position){

this.panel =new Ext.Panel({
renderTo: ct,
width:230,
height:50,
autoScroll:true,
layout:'vbox',
items:[]
//layout:'vbox',
});
this.el=this.panel.getEl();

//Ext.ux.form.ArrayField.superclass.onRender.call(this, ct, position);

this.hiddenField = Ext.DomHelper.append(this.el,{tag:'input', type:'hidden',name:this.name});
},

setValue:function(val) {

var v = Ext.util.JSON.encode(val);
this.hiddenField.value=v;
//alert(v);
//this.panel.removeAll();

for (var i=0;i<val.length;i++){
var f = new MyForm()
this.panel.add(f)
this.panel.doLayout();
f.setValues(val[i])
}

},

getValues:function(){
}
});

// register xtype
Ext.reg('arrayfield', Ext.ux.form.ArrayField);

</script>

<script type="text/javascript">

Ext.onReady(function(){

var f = new Ext.FormPanel({
labelWidth: 75,
url:'save-form.php',
frame:true,
title: 'Simple Form',
bodyStyle:'padding:5px 5px 0',
width: 350,
defaults: {width: 230},
defaultType: 'textfield',

items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank:false
},{
fieldLabel: 'Last Name',
name: 'last'
},{
fieldLabel: 'Company',
name: 'company'
}, {
fieldLabel: 'Email',
name: 'email',
vtype:'email'
}, new Ext.form.TimeField({
fieldLabel: 'Time',
name: 'time',
minValue: '8:00am',
maxValue: '6:00pm'
}),
this.a=new Ext.ux.form.ArrayField({name:'items',form:MyForm})
],

buttons: [{
text: 'Save',
handler: function(){
var i=0;
},
scope:this
},{
text: 'Cancel'
}]
});

f.render(document.body);

var rec={}
rec.data={
first:'John',
last:'Doe',
company:'Some Company',
email:'email@abc.com',
items:[{
phone:'11111111',type:'mobile'
},{
phone:'22222222',type:'office'
},{
phone:'33333333',type:'home'
}]
}

f.form.loadRecord(rec);

})


</script>

d0uble_hel1x
1 Sep 2009, 9:26 AM
i replied earlier but somehow it had to be approved by the moderator. any idea why is it so?

gerrye
16 Oct 2009, 7:40 PM
I had to patch onDestroy with these:



Ext.override(Ext.ux.ComponentListView, {
onDestroy : function(){
Ext.ux.ComponentListView.superclass.onDestroy.call(this);
Ext.destroy(this.components);
this.components = [];
},
});

Ext.override(Ext.ux.ComponentDataView, {
onDestroy : function(){
Ext.ux.ComponentDataView.superclass.onDestroy.call(this);
Ext.destroy(this.components);
this.components = [];
},
});

t800t8
18 Mar 2010, 9:09 PM
Sorry, it's my fault. Work properly :-)

Condor
18 Mar 2010, 10:24 PM
Seems it doesn't work with ComboBox. All options are available but the input field is empty even that field has value.

Are you sure the combobox store is loaded when the dataview is rendered?

(also see this feature request (http://www.extjs.com/forum/showthread.php?p=400274#post400274))

Animal
19 Mar 2010, 12:05 AM
This is really nice Condor. Could it be refactored as a layout class?

Condor
19 Mar 2010, 12:47 AM
This is really nice Condor. Could it be refactored as a layout class?

You mean HtmlLayout (http://www.extjs.com/forum/showthread.php?t=79191) or something different?

Animal
19 Mar 2010, 1:32 AM
Oh! I'd forgotten all about it! :"> :))

I think it ought to be part of the base library. HTML as scaffolding round Components is really useful for adding structure or hanging CSS styles off.

Animal
19 Mar 2010, 1:41 AM
they are not the same though. The ComponentDataView allows a <tpl for="."> to specify wrapping DOM for each newly rendered Component. The layout version requires that the wrapping DOM already be in place, and that each Component be programmatically targeted at an element.

Condor
19 Mar 2010, 3:29 AM
Are you suggesting a layout that has a template that is used for each item?

I could create one, but do you see a usecase?

Animal
19 Mar 2010, 4:00 AM
Yes, just like the ComponentDataView that incorporates a <tpl for ="."> to iterate over the Components it is rendering. And the Components could have a targetSelector config to select which element in that tpl they want to render into.

Condor
19 Mar 2010, 4:29 AM
The layout can't use a <tpl for="."> because you can also add/remove single items to/from a container, but I could create a layout that uses a template or HTML fragment to render each item to.

Animal
19 Mar 2010, 4:43 AM
As a kind of automatic wrapper of each Component? I'm just speculating really on what kind of things might make it easier for people.

daniel.rochetti
14 Apr 2010, 2:59 PM
Hey you all! I think a ComponentDataView is a must have feature, it should be part of the ExtJS framework, for sure. Do you remember the ZipWhip implementation showcase? http://www.extjs.com/blog/2009/05/27/implementation-spotlight-zipwhip-and-ext-js/
They "complain" about the lack of a Componente-capable DataView.
Imagine this very simple use-case:
- You want to build a DataView with your products, and in each element you'll have a StarRating component and a "Add to cart" button.

I think that the way to go is to provide a Component-Capable Template, extending the XTemplate, and them plug this layout inside the custom DataView.
Maybe the ZipWhip implementation can give us some ideas... but it is, indeed, a needed feature.

http://www.zipwhip.com/

Stju
19 Apr 2010, 11:33 PM
Someone before asked how to render component in different place, other than TD.. As the question remained unanswered, just posting some examples.
To render component in different place of template use CSS structural pseudo classes!
For example, to have component in 8th div in template :
renderTarget: 'div:nth(8)'
second li
renderTarget: 'li:nth(2)'
third child of foo
renderTarget: 'foo:nth-child(3)'

Condor
19 Apr 2010, 11:44 PM
I'm not a big fan of using 'nth', because changing your HTML markup would directly invalidate your render targets.

I would assign a class="my-target" to the target element and use a '.my-target' selector.

daniel.rochetti
20 Apr 2010, 12:17 AM
Hey guys,

I think rendering the component in diferent targets is not the real problem here. Try to think about the use case I said before: a DataView which display products as its items and each item will have its HTML markup as usual and two components: a button and a rating comp.

As a possible solution I think extending the XTemplate to provide component building capabilities, something like:


<tpl for".">
<div id="product_{id}">
<img />
<div>
<comp name="rating" />
</div>
<p>{name}</p>
<p>{shortDescription}</p>
<div>
<comp name="button" />
</div>
</div>
</tpl>

Then, when the template proccessor finds a <comp> tag it call a function, which is reponsible for building that component:

function(compName, values) {
// create the component and return so the template can render it
}

It should also provide some cache capability to avoid creating the same component for the same item more than one time. Probably it should handle unique IDs too, just like Ext does.
I'm not sure if I was clear in my example, but ASAP I'll work on some code.

Condor
20 Apr 2010, 12:50 AM
The template builder doesn't process HTML (that would be too slow). You can only do this as after-processing of a rendered template (like my ComponentDataView does).

Sesshomurai
6 May 2010, 4:17 PM
Hi,
This is cool. But I'm trying to make my component a resizable that wraps a <div thumb-wrap> in my template. Sorta like the image dataview demo. But the resizable needs an element when instantiated.

Any way to make this work with Resizable?

thanks!!!

Condor
6 May 2010, 10:12 PM
ComponentDataView only correctly handles components, so you would need to create a simple BoxComponent descendant that adds resizable support and use that in the dataview.

Sesshomurai
7 May 2010, 5:44 AM
Thanks Condor. I was reading the BoxComponent API.

For use in ComponentDataView, would I use something like "div:nth(0)" (since my template uses div's not tables) in the applyTo: or autoEl: section of BoxComponent? It didn't say if that kind of dom selector was supported.

Here's what I'm tinkering with now. The resizer and box component show, but _under_ the template element, not around it. My aim is to get the BoxComponent to surround each template item.



dataview = new Ext.ux.ComponentDataView({
store: store,
tpl: tpl,
autoHeight:true,
singleSelect: true,
overClass:'x-view-over',
itemSelector:'div.thumb-wrap',
emptyText: 'No images to display',
renderTarget: 'div:nth(0)',


prepareData: function(data){
return data;
},
items: [
new Ext.BoxComponent({
height:150,
width:70,
listeners: {
render: function() {
var resizer = new Ext.Resizable(this.getEl(), {
handles: 's e',
minWidth: 50,
height:100,
minHeight: 100,
maxWidth: 800,
maxHeight: 600,
pinned:true
});

}
}
})
],

Condor
7 May 2010, 6:13 AM
No, ComponentDataView will do the applyTo for you. You only need to specify a config object for your resizable component.

ps. I would use 'div:first' or simply 'div' (if there is only one div).

Condor
7 May 2010, 6:29 AM
Something like:

Ext.ux.ResizableComponent = Ext.extend(Ext.BoxComponent, {
afterRender: function() {
this.resizer = new Ext.Resizable(this.el, this.resizeConfig);
Ext.ux.ResizableComponent.superclass.afterRender.call(this);
},
beforeDestroy : function(){
Ext.destroy(this.resizer);
Ext.ux.ResizableComponent.superclass.beforeDestroy.call(this);
}
});
Ext.reg('ux.resizable', Ext.ux.ResizableComponent);

var dataview = new Ext.ux.ComponentDataView({
store: ['img1.gif', 'img2.gif', 'img3.gif'],
itemSelector: 'img',
tpl: '<img src="{field1}">',
items: [{
xtype: 'ux.resizable',
resizeConfig: {...},
applyTarget: '/'
}]
});
(warning: completely untested code!)

Sesshomurai
7 May 2010, 6:56 AM
genius in motion Condor.....it works.

Funny that you made an xtype for resizable because I started this by looking for one and didn't find it. Now I know how to do it!

webxells
24 Jun 2010, 1:48 AM
Wonderful work, thanks for that.
I insert buttons in a dataview, but I had a problem. Only one button was rendered in:

'<div class="DokumentListeInhalt">',
'<tpl for=".">',
'<tpl for="nodes">',
'<div class="DokumentInhaltNode">',
'<h1>{title}</h1>',
'<h2>{subtitle}</h2>',
'<p>{node_content}</p>',
'<div class="b"></div>',
'</div>',
'</tpl>',

'</tpl>',
'</div>'


items: {

xtype: 'compdataview',
store: xml_DokumentenInhalt_Store,
tpl: tpl_Dokument_Inhalt,
autoHeight : true,
itemSelector: 'div.DokumentInhaltNode',
cls: 'DataViewDokumentInhalt_Body',
singleSelect:true,

items: [{
text : 'Vergleiche mit',
xtype: 'button',
renderTarget: 'div.b'
}]
},


So I made an update on:

renderItems : function(startIndex, endIndex){
var ns = this.all.elements;

var endIndex = ns.length - 1;

because of the call: this.renderItems(0, this.store.getCount() - 1); gets only 1 element in my XML-Store.

Condor
24 Jun 2010, 3:04 AM
But you have a nested dataset (nodes inside records). That will never work correctly with a DataView!

Can you post your reader config and an example of your data?

webxells
24 Jun 2010, 3:35 AM
var xml_DokumentenInhalt_Store = new Ext.data.XmlStore({
autoLoad: false,
storeId : 'xml_DokumentenInhalt_Store',
url: 'data/example-full.xml',
record : '/',
fields : ['document_name',{
name: 'nodes',
convert: function(raw, item){
var nodes = Ext.DomQuery.select('node', item);

data = [];
Ext.each(nodes, function(node){
data.push({
id: node.getAttribute('node_id'),
title: Ext.DomQuery.selectValue('title', node),
subtitle: Ext.DomQuery.selectValue('subtitle', node),
node_content: Ext.DomQuery.selectValue('node_content', node),
//text: node.textContent || node.text,
});
});

return data;

}
}]

});


/**
* DataView Template
*/
var tpl_Dokument_Inhalt = new Ext.XTemplate(
'<div class="DokumentListeInhalt">',
'<tpl for=".">',
'<tpl for="nodes">',
'<div class="DokumentInhaltNode">',
'<h1>{title}</h1>',
'<h2>{subtitle}</h2>',
'<p>{node_content}</p>',
'<div class="btn" nodeid="{id}"></div>', //NodeID an Button anhängen
'</div>',
'</tpl>',

'</tpl>',
'</div>'
);

tpl_Dokument_Inhalt.compile();

... Window

xtype: 'compdataview',
id : 'DataViewDokumentInhalt',
store: xml_DokumentenInhalt_Store,
tpl: tpl_Dokument_Inhalt,
autoHeight : true,
itemSelector: 'div.DokumentInhaltNode',
cls: 'DataViewDokumentInhalt_Body',
singleSelect:true,

items: [{
text : 'Vergleiche mit',
xtype: 'button',
iconCls : 'btnVergleichen',
renderTarget: 'div.btn',
handler : onVergleicheMit

}]




data:



<?xml version="1.0" encoding="UTF-8"?>
<document document_id="34" >
<version_id>7</version_id>
<document_name>Dokument</document_name>
<release_date>2010-06-14</release_date>
<official_release>false</official_release>
<display_counter>
<level type="capital_letter"> <!-- A,B,C..for top level title counting -->
<level type="numeric" use_upper="false"> <!-- 1, 2, 3,.. for second level title counting; use_upper="false" means that the count from the upper level will not be used again -->
<level type="numeric" use_upper="true"/><!-- use_upper="true" means that the counter from the upper level will be used again => 1.1, 1.2,... -->
</level>
</level>
</display_counter>

<!--this is the root node; titles etc. will not be used at moment-->
<node node_id="0" type="structure">
<level>0</level>
<counter activate="false" manualChildCounter="false"/>
<title></title>
<subtitle></subtitle>
<origin_id>0</origin_id>
<ancestor_id>0</ancestor_id>
<subnodes><!-- Level 1: A-->
<node node_id="2" type="structure">
<level>1</level>
<counter activate="true" manualChildCounter="true">A</counter>
<!-- all children have manual counter e.g. §18a -->
<title>Paragraphenteil</title>
<subtitle></subtitle>
<origin_id>1</origin_id>
<ancestor_id>1</ancestor_id>
<comments>
<comment comment_id="12">
<comment_content>Das ist ein Kommentar ohne Anhang</comment_content>
<creation_date>2010-05-02</creation_date>
<user_name>uwe</user_name>
</comment>
<comment comment_id="13">
<comment_content>Das ist ein noch ein Kommentar ohne Anhang</comment_content>
<creation_date>2010-06-22</creation_date>
<user_name>test</user_name>
</comment>
</comments>
<subnodes> <!-- Level 2: manual counter - see parent node-->
<node node_id="10" type="text">
<level>2</level>
<counter activate="true">§1</counter>
<manualCounter activate="true">§1</manualCounter>
<title>Ziel</title>
<subtitle></subtitle>
<origin_id>10</origin_id>
<ancestor_id></ancestor_id>
<node_content><![CDATA[Ziel der Weiterbildung ist ...]]></node_content>
<comments>
<comment comment_id="14">
<comment_content>Das ist ein Kommentar</comment_content>
<creation_date>2010-06-23</creation_date>
<user_name>test</user_name>
<attachment attachment_id="16" >
<file_name>weiterbildung.rtf</file_name>
</attachment>
</comment>
</comments>
</node>
</subnodes>
</node>

<node node_id="3" type="structure"><!-- Level 1: B-->
<level>1</level>
<counter activate="true" manualChildCounter="false">B</counter>
<title>Gebiete-, Facharzt und Schwerpunktkompetenzen</title>
<subtitle></subtitle>
<origin_id>3</origin_id>
<ancestor_id></ancestor_id>
<subnodes>
<node node_id="100" type="structure"> <!-- Level 2: automatic counter 1,2,3.. -->
<lock username="herbert" />
<level>2</level>
<counter activate="true">1</counter>
<title>Gebiet Anästhesiologie</title>
<subtitle></subtitle>
<origin_id>100</origin_id>
<ancestor_id></ancestor_id>
<subnodes><!-- Level 3: automatic counter e.g.: 1.1,2.1,3.4. -->
<node node_id="300" type="text">
<lock username="herbert" />
<level>3</level>
<counter activate="false"/>
<title></title>
<subtitle></subtitle>
<creation_date>2010-06-22</creation_date>
<user_name>test</user_name>
<origin_id>80</origin_id>
<ancestor_id>90</ancestor_id>
<node_content><![CDATA[<h5>Definition:</h5>Das Gebiet Anästhesiologie umfasst ... ]]></node_content>
</node>
<node node_id="500" type="text">
<lock username="herbert" />
<level>3</level>
<counter activate="true">1.1</counter>
<title>Facharzt / Fachärztin für Anästhesiologie</title>
<subtitle>(Anästhesist / Anästhesistin)</subtitle>
<origin_id>399</origin_id>
<ancestor_id>399</ancestor_id>
<node_content><![CDATA[
<h5>Weiterbildungsziel:</h5>
<p>Ziel der Weiterbildung im Gebiet Anästhesiologie ist ...</p>
<h5>Weiterbildungszeit:</h5>
<p>60 Monate .... gemäß § 5 Abs. 1 Satz 1, davon
<ul>
<li>48 Monate im Gebiet Anästhesiologie, davon können bis zu</li>
<li>.... </li>
</ul>
</p>]]>
</node_content>
<comments>
<comment comment_id="76">
<comment_content>Das ist ein Kommentar: Diese beinhaltet keine Formatierung</comment_content>
<creation_date>2010-02-22</creation_date>
<user_name>test</user_name>
<attachment attachment_id="22" >
<file_name>weiterbildung.rtf</file_name>
</attachment>
<attachment attachment_id="24" >
<file_name>weiterbildung1.pdf</file_name>
</attachment>
</comment>
<comment comment_id="88">
<comment_content>Das ist ein weiterer Kommentar</comment_content>
<creation_date>2010-06-22</creation_date>
<user_name>test</user_name>
<attachment attachment_id="27" >
<file_name>mehr.doc</file_name>
</attachment>
</comment>
</comments>
</node>
</subnodes>

<comments>
<comment comment_id="34">
<comment_content>Das ist noch ein Kommentar</comment_content>
<creation_date>2009-02-21</creation_date>
<user_name>test</user_name>
</comment>
</comments>
</node>
</subnodes>
</node>
<node node_id="5" type="structure"><!-- Level 1: C -->
<level>1</level>
<counter activate="true" manualChildCounter="false">C</counter>
<title>Zusatz- und Weiterbildungen</title>
<subtitle></subtitle>
<origin_id>4</origin_id>
<ancestor_id>4</ancestor_id>
<comments>
<comment comment_id="129">
<comment_content>von Zusatz-Weiterbildungen geändert auf Zusatz- und Weiterbildung</comment_content>
<creation_date>2010-06-22</creation_date>
<user_name>herbert</user_name>
<attachment attachment_id="91">
<file_name>weiterbildung.pdf</file_name>
</attachment>
</comment>
</comments>
<subnodes> <!-- Level 2: 1,2,3 -->
<node node_id="101" type="text">
<lock username="ulli" />
<level>2</level>
<counter activate="true">1</counter>
<title>Gebiet Anästhesiologie</title>
<subtitle></subtitle>
<origin_id>101</origin_id>
<ancestor_id></ancestor_id>
<node_content><![CDATA[<h5>Definition:</h5>Das Gebiet Anästhesiologie .....]]></node_content>
<comments>
<comment comment_id="145">
<comment_content>Das ist ein Kommentar</comment_content>
<creation_date>2010-06-23</creation_date>
<user_name>test</user_name>
<attachment attachment_id="99">
<file_name>weiterbildung.rtf</file_name>
</attachment>
</comment>
</comments>
</node>
</subnodes>
</node> <!--end node 5 -->
</subnodes>
</node>
</document>




Thats it.

Condor
24 Jun 2010, 3:50 AM
To get a flat dataset you should configure your store with:

record : 'node',
fields: [
{name: 'document_name', mapping: function (node) {
return Ext.DomQuery.select('document_name', node.parentNode);
}},
{name: 'id', mapping: '@node_id'},
'title',
'subtitle',
'node_content'
]
(and remove <tpl for="nodes"> from your template)

webxells
24 Jun 2010, 5:08 AM
I did:



var xml_DokumentenInhalt_Store_Flat = new Ext.data.XmlStore({
autoLoad: true,
storeId : 'xml_DokumentenInhalt_Store_Flat',
url: 'data/example-full.xml',

record : 'node',
fields: [
{name: 'document_name', mapping: function (node) {
return Ext.DomQuery.select('document_name', node.parentNode);
}},
{name: 'id', mapping: '@node_id'},
'title',
'subtitle',
'node_content'
],
listeners: {
load: function() {
alert('test');
}
}

})

...


/**
* DataView Template
*/
var tpl_Dokument_Inhalt = new Ext.XTemplate(
'<div class="DokumentListeInhalt">',
'<tpl for=".">',

'<div class="DokumentInhaltNode">',
'<h1>{title}</h1>',
'<h2>{subtitle}</h2>',
'<p>{node_content}</p>',
'<div class="btn" nodeid="{id}"></div>', //NodeID an Button anhängen
'</div>',

'</tpl>',
'</div>'
);

tpl_Dokument_Inhalt.compile();

But nothing is loaded. The old code was:


var xml_DokumentenInhalt_Store = new Ext.data.XmlStore({
autoLoad: true,
storeId : 'xml_DokumentenInhalt_Store',
url: 'data/example-full.xml',
record : '/',
fields : ['document_name',{
name: 'nodes',
convert: function(raw, item){
var nodes = Ext.DomQuery.select('node', item);

data = [];
Ext.each(nodes, function(node){
data.push({
id: node.getAttribute('node_id'),
title: Ext.DomQuery.selectValue('title', node),
subtitle: Ext.DomQuery.selectValue('subtitle', node),
node_content: Ext.DomQuery.selectValue('node_content', node),
//text: node.textContent || node.text,
});
});

return data;

}
}],
listeners: {
load: function () { alert('test'); }
}

});

Any idea? The store data is empty, the second has data.

webxells
24 Jun 2010, 11:51 PM
Sorry, but nothing is loaded with this code above. I could not find an error.

Condor
25 Jun 2010, 12:48 AM
It really shouldn't be empty! How are you checking this?

ps. I made a small mistake on the document_name. It should be:

record : 'node',
fields: [
{name: 'document_name', mapping: function (node) {
while (node && node.tagName.toLowerCase() != 'document') {
node = node.parentNode;
}
return Ext.DomQuery.selectValue('document_name', node.parentNode);
}},
{name: 'id', mapping: '@node_id'},
'title',
'subtitle',
'node_content'
],

marcolara
25 Jun 2010, 9:43 AM
This is an amazing addition to the user library. I have a question regarding the implementation of ComponentDataView and radiogroup. I have the following code and the selectors on the radio buttons are not working because it sets the same radio button name for each record/combogroup found in the data set:


{
xtype: 'compdataview',
store: store,
tpl: this.testimonialRecordTmpl,
autoHeight: true,
multiSelect: false,
overClass: 'x-view-over',
itemSelector: 'div.story',
emptyText: '<h1>No Testimonials</h1><p>There are currently no testimonials to review</p>',
items: [{
xtype: 'radiogroup',
renderTarget: 'div.post_actions',
columns: 1,
items: [{
boxLabel: 'Post',
name: 'post',
inputValue: 1
}, {
boxLabel: 'Reject',
name: 'post',
inputValue: 0
}]
}]
}Is there a way to render components and dynamically assigning different component attributes (like id, name etc...) on each of them on the loop in order to avoid this kinds of problems?

webxells
30 Jun 2010, 4:24 AM
Hello,

I have a problem with complistview. Firebug say's:

component is undefined
chrome://firebug/content/blank.gif c = component.render ?

in 46

sourcecode from first page:

var component = columns[j].component;
c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);


How to use the extended ListView?

Condor
30 Jun 2010, 9:20 AM
Did you look at the ComponentListView example? You need to define a component for each column.

webxells
1 Jul 2010, 1:20 AM
Ups, sry :)

Let's try again ;).

Thanks.

webxells
1 Jul 2010, 1:44 AM
Is there a way to let component blank?

Condor
1 Jul 2010, 2:27 AM
Not in this version, you would need to modify renderItems for that to only render a component when one is defined.

webxells
1 Jul 2010, 2:42 AM
OK,

I did this:



renderItems : function(startIndex, endIndex){
var ns = this.all.elements;
var args = [startIndex, 0];
for(var i = startIndex; i <= endIndex; i++){
var r = args[args.length] = [];
for(var columns = this.columns, j = 0, len = columns.length, c; j < len; j++){
var component = columns[j].component;

//If no component is defined
if (component == undefined) {
return;
}

c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);
r[j] = c;
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
if(c.renderTarget){

//If no renderTarget was found - prevent errors
if (Ext.DomQuery.selectNode(c.renderTarget, node)) {
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}

}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, node));
}else{
c.render(node);
}
if(c.applyValue === true){
c.applyValue = columns[j].dataIndex;
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}
}
}
this.components.splice.apply(this.components, args);
}


So look at:


//If no component is defined
if (component == undefined) {
return;
}


and:


if (Ext.DomQuery.selectNode(c.renderTarget, node)) {
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}

So component will not be necessary.

webxells
1 Jul 2010, 2:48 AM
You guessed it:


//If no component is defined
if (component == undefined) {
continue;
}

Condor
1 Jul 2010, 3:44 AM
JSLint doesn't like that. You should write:

if (!component) {
continue;
}

webxells
3 Jul 2010, 9:07 AM
Is it possible to insert more than one component, like

var tpl_Template = new Ext.XTemplate(
'<tpl for=".">',

'<h1>{title}</h1>',

'<div class="btnEdit"></div>',

'<div class="more things">',

'<tpl for="comments">',
'<span class="date">{creation_date} {user_name}</span>',
'<p>{content}</p>',

'<div class="btnCommentEdit"></div>',

'</tpl>',
'</div>',

'</tpl>',
);

tpl_Template .compile();


var btnEdit= {
text : 'Edit',
xtype: 'button',
width: '125',
iconCls : 'IconKommentarBearbeiten',
renderTarget: 'div.btnEdit',
handler : function() {

}
}

...

xtype : 'complistview',

...

columns : [
{
xtype: 'lvcolumn',
header: 'Something',
dataIndex: 'temp',
tpl : tpl_Template,
component: [btnEdit, btnCommentEdit, btnSomething]
}
]


If I run this, there will only one textfield. But i.e. "btnCommentEdit" exists more than once.

webxells
4 Jul 2010, 12:38 AM
OK, I tried to find a solution for this:



renderItems : function(startIndex, endIndex){
var ns = this.all.elements;
var args = [startIndex, 0];
for(var i = startIndex; i <= endIndex; i++){
var r = args[args.length] = [];
for(var columns = this.columns, j = 0, len = columns.length, c; j < len; j++){
var component = columns[j].component;

//If no component is defined
if (!component) {
continue;
}

if (component.length > 1) {
var components = component;
for (var k = 0; k < components.length; k++) {
var component = components[k];

c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);
r[j] = c;
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
if(c.renderTarget){

//If no renderTarget was found - prevent errors
if (Ext.DomQuery.selectNode(c.renderTarget, node)) {
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}

}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, node));
}else{
c.render(node);
}
if(c.applyValue === true){
c.applyValue = columns[j].dataIndex;
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}

}
} else {

c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);
r[j] = c;
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
if(c.renderTarget){

//If no renderTarget was found - prevent errors
if (Ext.DomQuery.selectNode(c.renderTarget, node)) {
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}

}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, node));
}else{
c.render(node);
}
if(c.applyValue === true){
c.applyValue = columns[j].dataIndex;
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}

}

}
}
this.components.splice.apply(this.components, args);
},


It is useful. Can it be more smarter?

bartonjd
6 Jul 2010, 3:38 PM
I was playing around with your code Condor and couldn't quite get it to do what I needed so I have written this extension which is somewhat similar in nature. This extension lets the user define a template item for a tabpanel and then the template is used to build tabs for the tabpanel out of the store.

CODE WITH EXAMPLE:


Ext.ns('Ext.ux');
Ext.ux.TplTabPanel = Ext.extend(Ext.TabPanel, {
initComponent: function () {
//Ext.apply(this,{store:this.store});
Ext.ux.TplTabPanel.superclass.initComponent.apply(this, arguments);

var tb = this;
var itemArr = [];

var cnt = tb.store.getCount();

Ext.each(this.tabsTpl, function (j) {
for (var i = 0; i < tb.store.getCount(); i++) {


var c = j.render ? c = j.cloneConfig() : Ext.ComponentMgr.create(j);


function myfn() {
Ext.apply(this, tb.store.getAt(i).get(this.applyValues));
}
c.cascade(myfn);
Ext.ComponentMgr.register(c);

tb.items.add(c.id, c);

}
});

},
});
Ext.reg('tabtpl', Ext.ux.TplTabPanel);


Ext.onReady(function () {
new Ext.Viewport({
layout: 'hbox',
layoutConfig: {
align: 'stretch'
},
defaults: {
flex: 1
},
items: new Ext.ux.TplTabPanel({
id: 'climate_panel',
activeTab: 0,
store: new Ext.data.JsonStore({
storeId: 'weather',
data: [{
id: 'raw',
panel: {
title: 'Raw',
id: 'rawfield'
},
fieldset: {
title: 'Observed',
id: 'observed'
},
checks: {
items: [{
boxLabel: 'Precipitation',
id: 'chk1'
},
{
boxLabel: 'Temperature',
id: 'chk2'
}]
}
},
{
id: 'hourly',
panel: {
title: 'Hourly',
id: 'hourfield'
},
fieldset: {
title: 'Observed Hourly',
id: 'observed_hourly'
},
checks: {
items: [{
boxLabel: 'Altimeter'
},
{
boxLabel: 'Visibility'
}]
}
}],
fields: ['panel', 'title', 'id', 'cn', 'value', 'checks', 'fieldset', 'boxLabel', 'items'],

}),
tabsTpl: {
xtype: 'panel',
layout: 'form',
applyValues: 'panel',
items: {
xtype: 'fieldset',


applyValues: 'fieldset',
items: {
xtype: 'checkboxgroup',
//items:[],
applyValues: 'checks'
}
}
}
})


});
});

webxells
22 Jul 2010, 3:31 AM
Hello,

if someone comes to the point, to add more than one button in the list by using the renderTarget property, here is a solution:



Ext.ux.ComponentListView = Ext.extend(Ext.ListView, {
defaultType: 'textfield',
initComponent : function(){
Ext.ux.ComponentListView.superclass.initComponent.call(this);
this.components = [];
},
refresh : function(){
Ext.destroy(this.components);
this.components = [];
Ext.ux.ComponentListView.superclass.refresh.apply(this, arguments);
this.renderItems(0, this.store.getCount() - 1);
},
onUpdate : function(ds, record){
var index = ds.indexOf(record);
if(index > -1){
this.destroyItems(index);
}
Ext.ux.ComponentListView.superclass.onUpdate.apply(this, arguments);
if(index > -1){
this.renderItems(index, index);
}
},
onAdd : function(ds, records, index){
var count = this.all.getCount();
Ext.ux.ComponentListView.superclass.onAdd.apply(this, arguments);
if(count !== 0){
this.renderItems(index, index + records.length - 1);
}
},
onRemove : function(ds, record, index){
this.destroyItems(index);
Ext.ux.ComponentListView.superclass.onRemove.apply(this, arguments);
},
/**
* Workarround, um einen Destroy Fehler zu vermeiden
* Quelle: http://www.sencha.com/forum/showthread.php?79210-ComponentDataView-Ext-components-inside-a-dataview-or-listview
*/

onDestroy : function(){
Ext.ux.ComponentListView.superclass.onDestroy.call(this);
Ext.destroy(this.components);
this.components = [];
},
renderItems : function(startIndex, endIndex){
var ns = this.all.elements;
var args = [startIndex, 0];
for(var i = startIndex; i <= endIndex; i++){
var r = args[args.length] = [];
for(var columns = this.columns, j = 0, len = columns.length, c; j < len; j++){
var component = columns[j].component;

//If no component is defined
if (!component) {
continue;
}

if (component.length > 1) {
var components = component;
for (var k = 0; k < components.length; k++) {
var component = components[k];

c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);
r[j] = c;
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
if(c.renderTarget){

//If no renderTarget was found - prevent errors
if (Ext.DomQuery.jsSelect(c.renderTarget, node)) {
//c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
var elm = Ext.DomQuery.jsSelect(c.renderTarget, node);
Ext.each(elm, function(item) {
var nextEl = c.cloneConfig();
nextEl.render(item);
})
}

/*if (Ext.DomQuery.selectNode(c.renderTarget, node)) {
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}*/

}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, node));
}else{
c.render(node);
}
if(c.applyValue === true){
c.applyValue = columns[j].dataIndex;
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}

}
} else {

c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);
r[j] = c;
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
if(c.renderTarget){

//If no renderTarget was found - prevent errors
if (Ext.DomQuery.selectNode(c.renderTarget, node)) {
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}

}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, node));
}else{
c.render(node);
}
if(c.applyValue === true){
c.applyValue = columns[j].dataIndex;
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}

}

}
}
this.components.splice.apply(this.components, args);
},
destroyItems : function(index){
Ext.destroy(this.components[index]);
this.components.splice(index, 1);
}
});
Ext.reg('complistview', Ext.ux.ComponentListView);


The part:




//If no renderTarget was found - prevent errors
if (Ext.DomQuery.jsSelect(c.renderTarget, node)) {
var elm = Ext.DomQuery.jsSelect(c.renderTarget, node);
Ext.each(elm, function(item) {
var nextEl = c.cloneConfig();
nextEl.render(item);
})
}


Clones the button, so you can use it more than one time.

KRavEN
27 Jul 2010, 1:04 PM
Thanks for this Condor. For anyone wanting to add Ext.ux.RowActions type functionality to a ListView here is an example:


new Ext.ux.ComponentListView({
store : lbStore,
autoHeight : true,
emptyText : 'No VIP\'s to display',
columns : [{
header : 'VIP',
dataIndex : 'lb'
}, {
header : 'VIP Port',
dataIndex : 'lb_port'
}, {
header : '&nbsp;',
component : {
xtype : 'box',
autoEl: {
tag: 'img',
src: '/images/del-icon.png',
cls: 'row-action-del'
}
}
}],
listeners: {
click : {
fn: function(view, index, node, e) {
var el = Ext.get(e.target);
if(el.hasClass('row-action-del'))
{
var record = view.getRecord(node);
view.getStore().remove(record);
}
}
}
}
});

This needs the renderItems change from earlier in this thread

// If no component is defined
if (!component) {
continue;
}

base698
27 Jul 2010, 5:01 PM
I have a control that extends CustomDataView. The data in the control is about 200 records. It consists of a checkbox and a label. The control takes around 900 milliseconds for the renderItems function to load. It would be very nice if I could get that down to a more acceptable level.

Thanks,

Justin

base698
27 Jul 2010, 7:09 PM
I meant ComponenetDataView.

Condor
27 Jul 2010, 10:44 PM
Do you actually need Ext components, or could you just render HTML <label> and <input> elements in a normal DataView?

base698
28 Jul 2010, 3:41 AM
Not sure. The check box is actually a custom check box that can toggle through three types of checks.

aratcliffe
15 Feb 2011, 8:34 PM
I would like to set some properties of my components, such as visibility, based upon the properties of the record the component is being rendered for. How can I do this?

Cheers
Adam

Condor
16 Feb 2011, 12:30 AM
You could add a 'created' event to allow you to configure the component, e.g.:

...
r[j] = c;
this.fireEvent('created', this, c, i, j);
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
...

aratcliffe
17 Feb 2011, 7:15 PM
Thanks Condor, that solution works well :)

aratcliffe
15 Mar 2011, 8:48 PM
I'm seeing some strange behavior when using combos as a component inside a ComponentListView. An additional EM element is being created inside of the combo wrapper DIV and the trigger IMG is being rendered as a child of this EM element.

The generated markup is shown below:


<dt style="width: 50%; text-align: left;">
<em unselectable="on" id="ext-gen336">
<div class="x-form-field-wrap x-form-field-trigger-wrap" id="ext-gen337" style="width: 220px;">
<input type="text" name="ext-comp-1131" id="ext-comp-1131" autocomplete="off" size="24" class="x-form-text x-form-field x-trigger-noedit" style="width: 0px;" readonly="">
<em xmlns="http://www.w3.org/1999/xhtml" id="ext-gen338">
<img class="x-form-trigger x-form-arrow-trigger" alt="" src="js/ext-3.3.0/resources/images/default/s.gif">
</em>
</div>
</em>
</dt>

If I change this line
var node = ns[i].getElementsByTagName('dt')[j].firstChild; to
var node = ns[i].getElementsByTagName('dt')[j]; the combo is rendered correctly but I have some empty EM elements left in the DOM.

Does anybody know why this additional EM element is being created and how to resolve the issue cleanly?

Cheers
Adam

swarnendude
26 Apr 2011, 8:39 AM
While using a Ext Panel as a component of this component dataview, is it anyway possible to access the data inside the panel ? I am using this way:


items : [{
xtype : 'compdataview',
store : store,
itemSelector : 'div.image',
tpl : '<tpl for="."><div class="image">{id}</div></tpl>',
items : [{
xtype : 'panel',
title : 'Foo',
width : '100%',
bodyStyle : {
margin : '10px'
},
height : 100
}]
}]

I will have some combobox, textfields inside this 'Foo' panel and I need to show data of that corresponding record data in these fields.

zak_nuces
11 May 2011, 1:20 AM
I have tried to use ComponentDataView in IE and i am getting mixed content warning (over SSL) on IE . Particularly on IE7. I have tried to debug the problem and its happening in renderItem method. Please help.

vishnuhari333
28 Jun 2012, 1:23 AM
Hi,

I have a requirement to put textbox and chechbox inside the same column of a editor grid.
I have used simple renderer to put HTML components in the column.
But the problem is that data entered in the textbox is not getting saved to store.

Can I use the componentDataView/ComponentListView in a editorgrid?
Can you pls show me how to implemet this is a Grid?

I am using extjs 3.3.1

cedric.steiner
5 Aug 2012, 2:37 PM
Hi,

how can this be used in Sencha Architect?

I tried the following:

1. Create and include a js file with the code from the first post under "Ext.ux.ComponentListView"
2. Create Component View
3. Promote to Class
4. Give this new class the alias "complistview"
5. Add custom properties to the Component for "store", and "columns" and paste the values from the example in post 1.

There are no errors but also no list.
Am I doing something wrong?

Thanks

bartonjd
8 Aug 2012, 10:33 AM
Have you looked at the html source in firebug? Try putting some console.log statements in the render handler (in complistview file) and share your findings.

galdaka
13 Aug 2012, 3:33 AM
Same problem.

mikih
5 Oct 2012, 4:16 AM
Hi,

has anyone worked on something for ext js 4.x? I am thinking of porting the dataview from ST...


Cheers

Florian