I am working on my first project using ExtJS.
I have a Data Grid sitting inside a Tab that is inside a Window.
I want to add a link or button to the each element of the grid (I am using extended elements at the moment with HTML content through the RowExpander) that will make an AJAX call and open another tab.
I actually worked this out in the end. Pretty convoluted, and let's just say I will not be involving myself with ExtJS again if I can help it.
I am using the Grid.RowExpander to place HTML inside the Grid using XTemplate.
My links are therefore fairly straight forward:
Add to Cart
Where {product_id} is from JSON data loaded from an Ajax query. This is important, as you will see below.
Finding these events is much more difficult ... the Grid can tell you the row, but I actually needed to grab elements from a table inside the grid row. Long story, but I inherited some of this code.
Then in my parent component I have attached an event to the Grid itself.
this.on({
click :{scope: this, fn:this.actionGridClick}
});
To find the actual link, I search for the link in the target that has the correct class. In this case "add_cart_btn"
actionGridClick:function(e) {
// Looking for a click on a cart button
var addCartEl = Ext.get(e.getTarget('.add_cart_btn'));
if(addCartEl) {
productID = addCartEl.id;
// Once we have the ID, we can grab data from the data store
// We then call to the server to complete the "add to cart" functionality
}
}
Mpst of this is not very helpful except in my case, but it's here for posterity if anyone needs something similar in the future.
Try this :
// create grid
var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{header: 'NAME', width: 170, sortable: true, dataIndex: 'name'},
{header: 'PHONE #', width: 150, sortable: true, dataIndex: 'phone'},
{header: 'BIRTHDAY', width: 100, sortable: true, dataIndex: 'birthday',
renderer: Ext.util.Format.dateRenderer('d/m/Y')},
{header: 'EMAIL', width: 160, sortable: true, dataIndex: 'email',
renderer: renderIcon }
],
title: 'My Contacts',
autoHeight:true,
width:600,
renderTo: document.body,
frame:true
});
See this :
{header: 'EMAIL', width: 160, sortable: true, dataIndex: 'email', renderer: renderIcon }
the renderer will be defined as this :
//image path
var IMG_EMAIL = '/gridcell-with-image/img/email_link.png';
//renderer function
function renderIcon(val) {
return ''+ '<img src="' + IMG_EMAIL + '"> ' + val +'';
}
And here you are :)
If you are looking to add the link to the grid itself, you can specify another column in your ColumnModel and apply a renderer to the column. The function of the renderer is to return formatted content to be applied to that cell, which can be tailored according to the value of the dataIndex of the column (you should have a dataIndex, even if it is a duplicate of another column), and the record of that row.
function myRenderer(value,meta,record,rowIndex,colIndex,store){
// Do something here
}
Your link might have a click event to call a method, opening another tab
function myClickEvent(value1, value2){
var myTabs = Ext.getCmp('myTabPanel');
myTabs.add(// code for new tab);
}
If you're adding the links to your expanded area, within the RowExpander, then you'll have to write the rendering into the Template you're using for your expanded content area.
Related
I'm trying to render a form within a custom row grid without success.
handler: function (button, record, pressed, eOpts) {
var grid = this.up('grid');
var store = grid.getStore();
var innerPanel = Ext.widget('form', {
//renderTo: record,
title: 'Title Test',
name: 'test',
items: [{
xtype: "textfield",
name: "testfield",
fieldLabel: "FooTest"
}]
});
// store.add(record);
store.add(innerPanel);
}
Any idea how to do this?
Fiddle: https://fiddle.sencha.com/#fiddle/183e
Thanks.
EDITED with taubi19 sugestion.
I think you don't quite understand the concepts yet. The form is a part of the view, the store is an object, that takes care of the data. You want to have a column in which each row is a form. This means you need a column whose xtype is not textfield, but something custom. I found out on senchas kitchen sink, that we need a 'widgetcolumn ' . In your fiddle, change the columns array with the following code and you will have a form in each new row.
columns:[
{
header:'Name',
dataIndex:'name',
flex:1,
xtype:'widgetcolumn',
widget:{
width:400,
xtype:'form',
items:[
{
xtype:"textfield",
name:"testfield",
fieldLabel:"FooTest"
},
{
xtype:"textfield",
name:"testfield1",
fieldLabel:"FooTest1"
}
]
}
}
]
And I suggest you remove adding the form to the store. You add records/data to stores. The store.add method takes a model instance as a parameter (Ext.data.Store.add).
I'm working with this bootstrap library and actually everything works fine. The question is, Can bootstrap-table generate header automatically in depend of JSON file? I've tried to find any information about that, but unlucky. Now my header is generated from script like from this example:
function initTable() {
$table.bootstrapTable({
height: getHeight(),
columns: [{
field: 'field1',
title: 'title1',
sortable: true
}, {
field: 'field2',
title: 'title2',
sortable: true
}, {
field: 'field3',
title: 'title3',
sortable: true
}, {
field: 'Actions',
title: 'Item Operate',
align: 'center',
events: operateEvents,
formatter: operateFormatter
}
],
formatNoMatches: function () {
return "This table is empty...";
}
});
Does anyone how to generate header automatically?
Populating from a flat json file is definetly possible but harder than from a seperate (slimmer and preped) data request, because title and other attributes 'might' have to be guessed at.
Ill show basic approach, then tell you how to make it work if stuck with a flat file that you CAN or CANT affect the format of (important point, see notes at end).
Make a seperate ajax requests that populates var colArray = [], or passes direct inside done callback.
For example, in callback (.done(),.success(), ect) also calls to the function that contains the js init code for the table.
You might make it look something like this:
function initTable(cols) {
cols.push({
field: 'Actions',
title: 'Item Operate',
align: 'center',
events: operateEvents,
formatter: operateFormatter
});
$("#table").bootstrapTable({
height: getHeight(),
columns: cols,
formatNoMatches: function () {
return "This table is empty...";
}
});
}
$(document).ready(function(){
$.ajax({
method: "POST",
url: "data/getColumns",
// data: { context: "getColumns" }
datatype: "json"
})
.done(function( data ) {
console.log( "getCols data: ", data );
// Prep column data, depending on what detail you sent back
$.each(data,function(ind,val){
data.sortable = true;
});
initTable(data);
});
});
Now, if you are in fact stuck with a flat file, point the ajax towards that then realise the question is whether you can edit the contents.
If yes, then add a columns array into it with whatever base data (title, fieldname, ect) that you need to help build your columns array. Then use responseHandler if needed to strip that columns array if it causes issues when loading into table.
http://bootstrap-table.wenzhixin.net.cn/documentation/#table-options
http://issues.wenzhixin.net.cn/bootstrap-table/ (click 'see source').
If no, you cant edit contents, and only have the fieldname, then look at using that in the .done() handler with whatever string operation (str_replace(), ect) that you need to make it look the way you want.
I've been facing an issue on ExtJS while developing a UI:
I have a simple array which contains:
['1234','2345','3456']
I created a grid which loads some data, one of the columns in that grid should contain a combobox, which I already done by:
this.cellEditing = new Ext.grid.plugin.CellEditing({
clicksToEdit: 1
});
I have the editor with an empty store:
{text: "Tickets", renderer: Utils.renderCombo, dataIndex: 'ASSOC_TKT_NUMS', flex: 1,
editor: Ext.create('Ext.form.field.ComboBox', {
editable: false,
queryMode: 'local',
store: []
})
},
And on my method "renderCombo" I'm doing this, since I need to render my array in the store (which at first uses a [] as you can see above) :
renderCombo: function(value, meta, record) {
meta.column.editor.getStore().loadData(value);
}
But that does not seems to work, I even see my column empty, not a combobox.
Is there something I'm missing or something I need to change in my implementation?
Thanks in advance.
When you specify, that this column's editor field will be combobox, first of all you need to create Cell Editor and only then specify edit field
editor: Ext.create('Ext.grid.CellEditor', {
field: Ext.create('Ext.form.field.ComboBox', {
editable: false,
queryMode: 'local',
store: []
})
})
I have a simple Sencha App that has a main view. The view extends the Ext.navigation.View so that I can "push" to a new view when the user selects an item in the list. This happens by setting up a listener and then calling the push function on the MainView object.
However, I'm having problems getting the data across to that view. I tried using the answer from this StackOverflow question, but it didn't work.
In that answer it suggests that you use the record parameter of the itemTap() function, but this returns as an empty object.
Why does record return as an empty object?
Perhaps I'm going about this the wrong way?
In my case, I have a list of "brands", each with a title, image and description. I'd like to use that in the panel that slides in.
The launch function of my app which creates the view and ads to the viewport
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Create instance of the main view so we can use it's functions
SenchaTest.MainView = Ext.create('SenchaTest.view.Main');
// Initialize the main view
Ext.Viewport.add(SenchaTest.MainView);
},
Here is my view
Ext.define('SenchaTest.view.Main', {
extend: 'Ext.navigation.View',
xtype: 'main',
requires: [
'Ext.TitleBar',
'Ext.Video',
'Ext.carousel.Carousel',
'Ext.Img'
],
config: {
fullscreen: true,
items: [
{
title: 'Test',
layout: {
type: 'vbox',
align: 'stretch'
},
items: [{
xtype: 'highlightscarousel',
flex: 0.35
}, {
xtype: 'list',
displayField: 'title',
flex: 0.65,
store: Ext.create('SenchaTest.store.Brands'),
itemTpl: '<img src="{image}" class="listThumb"><h1 class="listTitle">{name}</h1><span class="clearFloat"></span>',
listeners: {
itemtap: function(nestedList, list, index, element, post, record) {
}
}
}]
}
]
}
});
Based on the Sencha Touch docs, the signature of the itemtap listener is:
(this, index, target, record, e, eOpts)
you're using:
(nestedList, list, index, element, post, record)
so that might be why the record is an empty object. If that's not the case, could you post a JSFiddle or some kind of working example of the problem?
I need to dynamically add a column to a page that has already been loaded. The column is represented by an object that is created AFTER the .ascx page is loaded (via user interaction). On the JavaScript side of things, I have a Panel with a TabPanel:
var reportPanel = new Ext.Panel({
layout: 'fit',
items: [
new Ext.TabPanel({
id: 'reportTabs',
renderTo: 'reportTabContainer',
activeTab: 0,
autoHeight: true,
minHeight: 600,
plain: true,
stateful: true,
deferredRender: false,//allows both reports to run at once
defaults:
{
autoHeight: true
},
items: tabsConfig
})
]
});
};
an item in tabsConfig looks like this:
{{ id: 'totalOperation', title: 'Total Operation', autoLoad: {{url: '" +Url.Action("Detail","OverallReport") +"', params: 'null', scripts: true, timeout: '9000000', method: 'POST'}}
My problem is that once the column object has been created, I need to re-render the ascx page (aka the extJSpanel) after a specific AJAX call. I have tried panel.removeAll(true) as well as panel.doLayout(false,true), and that does not remove any of the elements in the panel, or refresh the page.
In short--I need to destroy an .ascx page before an AJAX call to the controller, and let the return of the AJAX call re-populate the ascx control (using return PartialView(...) ).
Any suggestions would be greatly appreciated.
Answered my question-this little snippet of code solved it:
var contentPanel = Ext.getCmp('totalOperation');
contentPanel.autoLoad = {
url: 'URL path of controller method'
};
contentPanel.doAutoLoad();