I have the following application: https://fiddle.sencha.com/#view/editor&fiddle/1nmm. I'm using extjs 6.
After double click event on a row, I want to open a new tab. The new tab should contain a form with the information from the grid. My problem is that when I try to bind the displayfield value, the output is empty( nothing is shown).
xtype: 'displayfield',
fieldLabel: 'Id',
bind: {
value: '{record.data.ts_id}'
}
The above 'record' is declared as follow:
config: {
record: null,
rowIndex: null
},
bind: {
record: '{recordVM}',
rowIndex: '{rowIndexVM}'
}
How to properly bind to displayfield's value?
2 things:
1) Modify the way you're passing data to the viewmodel in the TabUIController:
viewModel: {
data: {
record: record,
rowIndex: rowIndex
}
}
There's no point trying to re-map those things.
2) Modify the bind statement in your view to value: '{record.ts_id}', the binding is smart enough to drill into the fields when it sees a record.
Try this:
TabUIGrid.js
bind: {
store :'{users}',
selection : '{myrecord}'
},
TabFormTest.js
{
xtype: 'displayfield',
fieldLabel: 'Name',
bind: '{myrecord.ts_name}'
}, {
xtype: 'displayfield',
fieldLabel: 'Email',
bind: '{myrecord.ts_email}'
}
I tested it on your fiddle and it works fine.
Related
I have 3 field like this:
{
name: 'firstName',
fieldLabel: 'First name',
bind: '{person.firstName}',
xtype: 'textfield',
allowBlank: false,
listeners: {
blur : {
buffer : 1000,
fn : 'detectGender'
},
}
},
{
name: 'middleName',
fieldLabel: 'Middle name',
bind: '{person.midleName}',
xtype: 'textfield',
allowBlank: true,
listeners: {
blur : {
buffer : 1000,
fn : 'detectGender'
},
}
},
{
name: 'lastName',
fieldLabel: 'Last name',
bind: '{person.lastName}',
xtype: 'textfield',
allowBlank: true,
listeners: {
blur : {
buffer : 1000,
fn : 'detectGender'
},
}
},
And I have a function to determine the gender of the user:
detectGender: function () {
const vm = this.getViewModel()
const firstName = vm.get('person.firstName');
const lastName = vm.get('person.lastName');
const personName = `${firstName ? firstName : ' '}${middleName ? middleName : ' '}${lastName ? lastName : ' '}`
if (firstName) {
//ajax request to server with data: personName
// personName migth be SarahSmith, or Sarah, or SarahEllen, or SarahEllenSmith
}
},
It works, but my problem is that function 'detectGender' runs all three times if all these fields are filled in. And my server returns three responses. But i need run this only one time. Maybe there is some way to create an event for the viewmodel to listen when person name has been changed?
Or any ideas on how to send the user name from the three fields only once?
Hope i was clear enoght... Please any help
I think Arthur's comment is probably the simplest way to solve the issue.
However, here's a couple more options.
Opt1 - You could put each of the name fields in a "parent" and listen to the "blur" event on the parent. In the sencha fiddle example, look at the code "Opt1" which I've set up with a "fieldcontainer". Since a container doesn't have a "blur" event, the "focusleave" event is used. I think of my two options, this would be the best as it gives you a good indication the user is done entering the name.
// Opt 1: Detect "blur" on higher level element
// so you know user is done
xtype: 'fieldcontainer',
layout: 'hbox',
fieldLabel: 'Name',
listeners: {
// "Opt1: blur equivilent" for a container
focusleave: 'detectGender'
},
items: [{
name: 'firstName',
emptyText: 'First',
bind: '{person.firstName}',
xtype: 'textfield',
allowBlank: false
}, {
name: 'middleName',
emptyText: 'Middle',
bind: '{person.middleName}',
xtype: 'textfield',
allowBlank: true
}, {
name: 'lastName',
emptyText: 'Last',
bind: '{person.lastName}',
xtype: 'textfield',
allowBlank: true
}]
}
Opt2 - You brought up listening to the viewModel data. I've provided an example of this, but it's basically a "change" event, so you'd get an event each time someone typed a letter in the field, resulting in a similar problem you have now. I did an example for fun, with a throttled function to help delay, but I think you'd end up calling the server way too much as unlike the above, you don't know when someone is "done" entering the name.
This uses the bindings config on a ViewController, which is a convenience for manually calling viewModel.bind(), which is how you can "listen" to viewModel data.
Ext.app.ViewController - bindings config
Ext.app.ViewModel - bind method
Here's the fiddle, hopefully it's not too confusing having both examples in one.
Sencha Fiddle
In an Ext.grid.panel I load a list of contents as rows with several columns. I would like the user to be able to select only one of these rows via a checkbox/radiogroup column, which has the ID of the respective entry as value.
I have already discovered the radiobuttons via the xtype widgtecolumn. But how can I set this column so that only one radiobutton in this column can be activated?
The current code for the radio column is the following:
{
xtype: 'widgetcolumn',
bind: {
text: 'Select topic'
},
dataIndex: 'defaultTopic',
widget: {
xtype: 'radio',
simpleValue: true
}
}
To ensure that the user can select only one radiobutton, you have to add the name property to your radio widget.
If you were using radiogroups like in this example, you'd have to add the name to each radiobutton. But for your use case, this configuration would be sufficient:
widget: {
xtype: 'radio',
simpleValue: true,
name: 'test'
}
See also this fiddle for an example.
You can use checkcolumn and change the records values that controls the check value using checkchange listener
Example:
{
xtype: 'checkcolumn',
text: 'Active',
dataIndex: 'active',
listeners: {
checkchange: 'onChangeDefaultTopic'
}
}
In your view controller:
onChangeDefaultTopic: function (column, rowIndex, checked, record) {
if (checked) {
store.getRange().forEach((rec) => {
if (record.get('id') !== rec.get('id')) {
rec.set('active', false)
}
});
}
}
I'm new to ExtJS. So finding little difficult in understanding many things.
I've a sample combo box where I'm retrieving datas from the table
This is the combo box:
xtype: 'fieldset',
title: 'Dress Type',
items: [{
xtype: 'combobox',
name: 'dresses',
forceNewStore: true,
queryMode: 'local',
displayField: "description",
valueField: "description",
mapperId: 'getavailabletype',
emptyText: 'Select Type
forceSelection: true,
maskRe: /[A-Za-z0-9]/,
margin: '15px',
allowBlank: false,
triggers: {
clear: {
cls: 'x-form-clear-trigger',
handler: function() {
this.reset();
}
}
},
}]
Here is the way I'm trying to retain the first value of the table:
me.down("combobox[name=dresses]").setValue(me.down("combobox[name=dresses]").store.getAt('0').get('description'));
I'm getting:
Uncaught TypeError: Cannot read property 'get' of null #getAt('0')
Please help
I don't know from what listener and component you are trying to achieve this, but from my perspective, the best place to achieve this is in the "render" event listener of the combobox.
Like so:
listeners: {
'render': function(combo) {
combo.setValue(combo.getStore().first());
}
}
Here you have a working fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1qqk
OR
If you have a reference to the combo store, let's say it's in the comboStore variable, you can set the first value like this:
{
xtype: 'combobox',
value: comboStore.first()
}
Another fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1qql
Now, if you are not sure that the store will be loaded by the time you initialize your combo, you can set the following listener for the combobox:
listeners: {
render: function(combo) {
var store = combo.getStore(),
setFirstStoreValFn = function() {
combo.setValue(store.first());
};
if (store.getCount()) {
setFirstStoreValFn();
}
else {
store.on('load', setFirstStoreValFn, null, {single: true})
}
}
}
So basically, it creates a reusable function that sets the combo value to the first record in the store, and then it checks if the store has records (which means that is has been loaded) it will call the function, if not - it will set a single load listener on the store which will then call the set value function.
Again, the fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1qqm
you need to navigate to cmp --> store --> first record ---> data
for that me.down("combobox[name=dresses]").store.getAt(0).get('description'))
I am implementing a RowEditing functionality
Here is one of the grid column
header: 'City', dataIndex: 'City_id',
editor: {
xtype: 'combobox',
queryMode: 'local',
displayField: 'text',
valueField: 'value',
store: Ext.create('Ext.data.Store', {
fields: ['text', 'value'],
data: [
{ text: 'Atlanta', value: '1' },
{ text: 'New York', value: '2' }
]
})
}
Stored procedure returns only city Id, that is 1 or 2. Now because I used " dataIndex: 'City_id' " at the header - only 1 or 2 is binding to the grid.
My question here is, in this I want to bind text not value to the display. How can I do this? Please suggest me.
Usually you would use a renderer on the column to display the text instead of the value.
Something along the lines of:
renderer:function(value) {
return this.editor.store.findRecord("value",value).get("text");
}
#Alexander's answer is the right way to go for updating the displayed value in the column.
To fix the issue with the column header, use the text property, not the header property, in the first line of your code sample.
Column config:
{ text: 'City', // NOT header: 'City'
dataIndex: 'City_id',
editor: {
...
}
}
I have a requirement to display combobox and datefield in Grid columns. So used widgetcolumn and created grid with those fields.
But now on changing data in combobox or datefield, new values should be updated in grid store so that after going to next page and coming back, values should persist in previous pages.
Can someone let me know how I can achieve this?
Fiddle: https://fiddle.sencha.com/#fiddle/183r
Option1: Use both widget and cell editor.
Add CellEditing plugin and set editor to same component as widget.
{ xtype: 'widgetcolumn', text: 'Gender', dataIndex: 'gender', flex: 1,
widget: { xtype: 'combo', store: genderStore, displayField: 'name', valueField: 'value'},
editor: { xtype: 'combo', store: genderStore, displayField: 'name', valueField: 'value'}
},
Example: https://fiddle.sencha.com/#fiddle/1843
Option2: Manually update the record.
I feel this solution is better.
widget: {xtype: 'datefield',
listeners:{
select: function(datefield, value, eOpts){
var rowIndex = datefield.up('gridview').indexOf(datefield.el.up('table'));
var record = datefield.up('gridview').getStore().getAt(rowIndex);
record.set('dob', value);
}
}
}
Example: https://fiddle.sencha.com/#fiddle/1842
To get rowIndex in widgetColumn, I referenced "How to get rowIndex in extjs widget column" DrakeES's answer.
The best solution i could find.
The function "getWidgetRecord" is not findable with the search.
It is discribed within the widget config description.
Have a look at the following Links.
https://docs.sencha.com/extjs/5.1.3/api/Ext.grid.column.Widget.html#cfg-widget
https://docs.sencha.com/extjs/6.0.2/classic/Ext.grid.column.Widget.html#cfg-widget
A config object containing an xtype.
This is used to create the widgets or components which are rendered into the cells of this column.
This column's dataIndex is used to update the widget/component's defaultBindProperty.
The widget will be decorated with 2 methods: getWidgetRecord - Returns
the Ext.data.Model the widget is associated with. getWidgetColumn -
Returns the Ext.grid.column.Widget the widget was associated with.
widget:{
xtype:'combo',
editable: false,
store: Ext.create('Ext.data.Store',{
fields:['name','text'],
data:[
{"name":"integer", "text":"Integer"},
{"name":"float","text":"Float"}
]
}),
listeners:{
select: function(combo, value, eOpts){
var record = combo.getWidgetRecord();
record.set('type', value.get('name'));
}
},
valueField:'name',
displayField:'text',
allowBlank: false
}
or
widget: {
xtype: 'textfield',
allowBlank: false,
listeners:{
change: function(textfield, value, eOpts){
var record = textfield.getWidgetRecord();
record.set('field', value);
}
}
}