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).
Related
I am trying to render some data in tabular form using react-bootstrap-table but the data of one column is overlapping with the data of other columns. i wanted to keep my layout fixed and thus have added the css layout:fixed which is actually a requirement as well. But the final result is:
Actually for this column i'm getting an array of string from backend. e.g. ["DEPT","OLD","CUSTOM_FUNCTION",...] which is getting converted into a single string internally by react and i'm not sure how to further format it.
I also searched in react table docs at : https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-celledit.html#rich-editors but didn't find anything.
My ultimate goal is to visualize the data in a much better way like drop down or each element of array in new line within the same column expandable on some mouse click.
The above image can be considered as sample requirement where only the first element of list will be displayed on load and after clicking on arrow button it will show all the list items below one another in the same column as shown below.
I am not able to figure out which column prop will help me or whether it's even possible or not. The goal is exactly the same but a simple new line separated data will also do.
Column Definition Code:
{
dataField: 'data',
text: 'DATA',
editable: false,
filter: textFilter(),
headerStyle: () =>
{
return { width: '100px', textAlign: 'center'};
}
}
Table Creation Code:
<BootstrapTable
keyField='serialNo'
data={ this.state.data }
columns={ this.state.columns }
filter={ filterFactory() }
pagination={ paginationFactory({sizePerPage: 4}) }
cellEdit={ cellEditFactory({ mode: 'click'}) }
striped
hover
/>
Kindly help or suggest something appropriate.
Thanks
Check this sandbox.
https://codesandbox.io/s/competent-rain-2enlp
const columns = [{
dataField: 'id',
text: 'Product ID',
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'labels',
text: 'Labels',
formatter: (cell) => {
return <>{cell.map(label => <li>{label}</li>)}</>
},
}];
You need to define your own formatter in order to include "complex" html inside your table cell.
So what I'm trying to achieve is to populate the Form with the selected row records and/or to edit the rows through form, via the ViewModel so it's two-way binding, I have done soo in the states field but I'm having trouble with the other fields, I have tried formulas but that didn't work either.
Here is a handler that did console the records but I can't bind them with the form fields.
store = this.getView().getStore();
var records = record.getSelected().items[0].data;
//var record = records[0];
console.log('showChart',records)
if (records) {
this.getView().getDialog().loadRecord(records);
}
console.log(records.name);
Here is my Fiddle example
You need to transport the selected record to the form and also set the bind (bind: {value: ''}) property of the form fields.
A simple way is to pass the selected grid record to the Test.main.Form's viewModel. Look:
mainController.js:
...
showChart: function (record, selModel) {
var form = Ext.create({
xtype: 'testform'
});
//selModel is actually an array of selected records.
form.getViewModel().set('record', selModel[0]);
form.show();
},
...
form.js:
...
items: [{
label: 'First Name',
name: 'first',
bind: {
//record that was set in the showChart function.
value: '{record.name}'
}
...
Try with the other fields.
I hope this helps. Any questions, let me know.
Ok I'm pretty sure I know exactly what I need to do here but I'm not sure how to do it. Basically I have a grid that I want to make a key column bind to an array of key/values, which I've done before with kendo (not using Angular) and I know that when I'm creating my key/value array asynchronously then that needs to complete before I can get them show-up with kendo, which I have done using promises before.
So here I have the same issue only angular is also involved. I need to fetch and format an array of data into the format in which a kendo grid column can digest it, so no problem here is my controller code:
var realm = kendo.data.Model.define({
id: 'realmID',
fields: {
realmID: { editable: false, nullable: true }
realmType: { type: 'string', validation: { required: true } }
}
})
var ds1 = kendoHelpers.dataSourceFactory('realms', realm, 'realmID')
var realmType = kendo.data.Model.define({
id: 'realmTypeID',
fields: {
realmTypeID: { editable: false, nullable: true },
name: { type: 'string', validation: { required: true } }
}
})
var ds2 = kendoHelpers.dataSourceFactory('realms/types', realmType, 'realmTypeID')
$scope.mainGridOptions = {
dataSource: ds1,
editable: true,
navigatable: true,
autoBind:false,
toolbar: [
{ name: "create" },
{ name: 'save' },
{ name: 'cancel' }
],
columns: [
{ field: 'realmID', title: 'ID' }
{ field: 'realmTypeID', title: 'Realm Type', editor: realmTypesDDL, values: $scope.realmTypeValues },
{ command: "destroy" }
]
}
$scope.secondGridOptions = {
dataSource: ds2,
editable: true,
navigatable: true,
toolbar: [
{ name: "create" },
{ name: 'save' },
{ name: 'cancel' }
],
columns: [
{ field: 'realmTypeID', title: 'ID' },
{ field: 'name', title: 'Name' }
{ command: "destroy" }
]
}
ds2.fetch(function () {
$scope.realmTypeValues = [{ text: 'Test', value: "24bc2e62-f761-4e70-804c-bc36fdeced3d" }];
//this.data().map(function (v, i) {
// $scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID})
//});
//$scope.mainGridOptions.ds1.read()
});
function realmTypesDDL(container, options) {
$('<input />')
.appendTo(container)
.kendoDropDownList({
dataSource: ds2,
dataTextField: 'name',
dataValueField: 'realmTypeID'
});
}
I made this dataSourceFatory helper method above to return me a basic CRUD kendo dataSource that uses transport and also injects an authorization header which is working fine so don't get hung up on that, ultimately I'm going to be using this data in another grid as well as for reference values for the main grid, but I've hard coded some values that I can use to test with in the ds2.fetch callback.
My HTML is pretty plain:
<div>
<h2>Realms</h2>
<kendo-grid options="mainGridOptions"></kendo-grid>
<h2>Realm Types</h2>
<kendo-grid options="secondGridOptions"></kendo-grid>
</div>
This all works fine and well except I am only seeing the GUID of the realmTypeID in the grid, I click it and the editor is populated correctly so that's good but I want the text value to be displayed instead of the GUID. I'm sure the issue is that the array of values is empty whenever angular is binding to the grid options. My questions are:
How do I either delay this bind operation or manually rebind it after the fetch call?
Is there a better way to handle a situation like this? I try not to expend finite resources for no reason (IE making server calls when unnecessary)
Note: When I move the creation of the text/value array to happen before the grid options, I get the desired behavior I am after
EDIT A work around is to not use the directive to create the grid and instead defer the grid creation until the callback of whatever data your column is dependent on, I was hoping for a more elegant solution but this is better than nothing. So your HTML becomes something like
<h2>Realms</h2>
<div id="realms"></div>
<h2>Realm Types</h2>
<kendo-grid options="secondGridOptions"></kendo-grid>
Then you can create the grid in the fetch callback for example:
ds2.fetch(function () {this.data().map(function (v, i) {
$scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID})
});
$('#realms').kendoGrid($scope.mainGridOptions);
$scope.mainGridOptions.dataSource.fetch()
});
But this doesn't feel very angularish so I'm really hoping for a better solution!
Ok...well I think I hacked this enough and without another suggestion I'm going to go forward with this approach. I'm just going to move the binding logic to the requestEnd event of the second grid so that the values array can be populated right before the binding even. I'm also reworking the values array in this method. It is a bit weird though, I think there is some kendo black magic going on with this array because I can't just set it to a new empty array without it breaking completely...which is why I'm poping everything out prior to repopulating the array. That way when something is deleted or edited in the second grid, the DDL in the first grid is updated in the callback.
function requestEnd(e) {
for (var i = $scope.realmTypeValues.length; i >= 0; i--) $scope.realmTypeValues.pop();
var data;
if (e.type == "read")
data = e.response;
else
data = e.sender.data();
data.map(function (v, i) { $scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID }); });
if ($('#realms').data('kendoGrid') == undefined) {
$('#realms').kendoGrid($scope.mainGridOptions);
}
else
$('#realms').data('kendoGrid').columns[4].values = $scope.realmTypeValues;
}
ds2.bind('requestEnd', requestEnd);
So I'm going to accept my own answer unless anyone has a better approach!
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 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.