In the window for creating and editing records, I have a combobox type field
Ext.define('BookApp.view.Book', {
extend: 'Ext.window.Window',
alias: 'widget.bookwindow',
width : 450,
title: 'Book',
layout: 'fit',
autoShow: true,
modal : true,
initComponent: function() {
this.items = [{
xtype: 'form',
items: [
{
xtype: 'combobox',
fieldLabel: 'Status',
name: 'status',
store: Ext.data.StoreManager.lookup('Statuses'),
valueField: 'id',
displayField: 'name',
typeAhead: true,
queryMode: 'remote'
},
...............
Store Statuses gives records from the table with the fields: id, name, order_install, where order_install is the order of the status.
Table Statuses
id name order_install
23 New 1
24 In Work 2
29 Postponed 3
34 Shipped 4
31 In_transit 5
How to make that the choice of a value from the status list was limited to only one value up or down according to the order_install field?
For example: If the status of In Work, then only the statuses Postponed and New were available for selection
Solution:
Use store filterBy() method with custom filtering function.
Because your id values are random, you have to get the internal position of record in store to find the prior and next record.
In the next examples filterCombo() is the function, that filters the store. This function is used in combobox select event. You can use it where you want. There are differences between ExtJS 4 and ExtJS 6 version, so there are two examples:
ExtJS 4:
Ext.onReady(function(){
Ext.QuickTips.init();
Ext.FocusManager.enable();
var store = Ext.create('Ext.data.Store', {
fields: ['order', 'id', 'name'],
data : [
{"id": 23, name: "New", order_install: 1},
{"id": 24, name: "In Work", order_install: 2},
{"id": 29, name: "Postponed", order_install: 3},
{"id": 34, name: "Shipped", order_install: 4},
{"id": 31, name: "In_transit", order_install: 5}
]
});
function filterCombo(combobox, index) {
store = combobox.getStore();
store.clearFilter();
store.filterBy(
function(record) {
if ((record.index == index - 1) || (record.index == index) || (record.index == index + 1)) {
return true;
} else {
return false;
}
}
);
};
Ext.create('Ext.form.ComboBox', {
fieldLabel: 'Choose items',
store: store,
queryMode: 'local',
displayField: 'name',
valueField: 'id',
multiSelect: false,
renderTo: Ext.getBody(),
value: 'In Work',
listeners: {
'select': function (combo, records) {
index = records[0].index;
filterCombo(combo, index);
},
'render': function (combo) {
index = combo.store.find('name', combo.getValue());
filterCombo(combo, index);
}
}
});
});
ExtJS 6:
Ext.application({
name : 'Fiddle',
launch : function() {
var store = Ext.create('Ext.data.Store', {
fields: ['order', 'id', 'name'],
data : [
{"id": 23, name: "New", order_install: 1},
{"id": 24, name: "In Work", order_install: 2},
{"id": 29, name: "Postponed", order_install: 3},
{"id": 34, name: "Shipped", order_install: 4},
{"id": 31, name: "In_transit", order_install: 5}
]
});
function filterCombo(combobox, index) {
store = combobox.getStore();
store.clearFilter();
store.filterBy(
function(record) {
if ((record.internalId == index - 1) || (record.internalId == index) || (record.internalId == index + 1)) {
return true;
} else {
return false;
}
}
);
};
Ext.create('Ext.form.field.ComboBox', {
fieldLabel: 'Choose items',
store: store,
queryMode: 'local',
displayField: 'name',
valueField: 'id',
value: '24', // Equals to "In Work"
multiSelect: false,
renderTo: Ext.getBody(),
listeners: {
'select': function (combo, records) {
index = records.internalId;
filterCombo(combo, index);
},
'render': function (combo) {
index = combo.getSelection().internalId;
filterCombo(combo, index);
}
}
});
}
});
So i have two solutions, one to prevent selecting the combo item(but it will remain visible) and the other to hide the values you don't want to be selected(using store filters).
1) FIDDLE: beforeselect
2) FIDDLE: filterBy
Related
I have a grid that when is clicked change the property cellwrap from false to true
onCellClick: function(view, td, index, record, tr, rindex) {
var
me = this,
vm = me.getViewModel(),
field = me.lookupReference('descriptionField');
field.cellWrap = true;
field.getView().getStore().getSource().reload();
}
But i guess im making it wrong. Can i reload the grid with the cellwrap propertie change? Im using the v7.5.1.20
cellWrap is a configuration of an Ext.grid.column.Column. You can't simply change it after the grid is rendered, you need to use the reconfigure method of Ext.grid.Panel to update the columns and set cellWrap to true.
You can try this code in a Sencha Fiddle (ExtJS 7.4.0 modern material), click anywhere and see how the top left cell is changing:
Ext.application({
name: 'Fiddle',
launch: function () {
const store = new Ext.data.Store({
fields: ['name', 'phone'],
data: [{
name: 'Name1 Name1 Name1 Name1 Name1 Name1 Name1 Name1 Name1 Name1 Name1 Name1',
phone: 111
}, {
name: 'Name2',
phone: 222
}, {
name: 'Name3',
phone: 333
}, {
name: 'Name4',
phone: 444
}, {
name: 'Name5',
phone: 555
}]
})
const myGrid = Ext.create({
renderTo: Ext.getBody(),
xtype: 'grid',
store: store,
selModel: 'cellmodel',
columns: [{
text: 'Name',
dataIndex: 'name',
cellWrap: false
}, {
text: 'Phone',
dataIndex: 'phone'
}],
listeners: {
cellclick: function (table, td, cellIndex, record, tr, rowIndex, e, eOpts) {
myGrid.reconfigure(null, [{
text: 'Name',
dataIndex: 'name',
cellWrap: true
}, {
text: 'Phone',
dataIndex: 'phone'
}]);
}
}
});
}
});
I have an example of ui-grid that one of the column represent sex type ('Gender':male , female..).
The json data that binding to the grid contain just the code type like (1, 2, 3...)
But I want to display the sex name like 'male' if the code is 1 and so on
And when the user choose from list new gender i want to display the new sex name
And update the sex code in the json data.
In fact, it was so far when I used basic HTML table (I add example in plnkr link)
any idea ?
// Code goes here and link for plunker :http://plnkr.co/edit/g6xYama3MidekeDqI3p8?p=preview
var app = angular.module('app', ['ngAnimate', 'ui.grid', 'ui.grid.edit','ui.grid.cellNav']);
app.controller('MainCtrl', ['$scope', '$http',
function($scope, $http) {
$scope.genderTypes = [{
ID: 1,
type: 'male'
}, {
ID: 2,
type: 'female'
}, {
ID: 3,
type: 'both'
}, {
ID: 4,
type: 'none'
}, ];
$scope.gridOptions = {
enableSorting: true,
enableFiltering: true,
enableCellEditOnFocus: true,
columnDefs: [{
field: 'name',
sort: {
direction: 'desc',
priority: 1
}
}, {
field: 'gender',
editType: 'dropdown',
enableCellEdit: true,
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownOptionsArray: $scope.genderTypes,
editDropdownIdLabel: 'ID',
editDropdownValueLabel: 'type'
}, {
field: 'company',
enableSorting: false
}],
onRegisterApi: function(gridApi) {
grid = gridApi.grid;
}
};
$scope.gridOptions.data = [ { "name": "Ethel Price", "gender": "1", "company": "Enersol" }, { "name": "Claudine Neal", "gender": "2", "company": "Sealoud" }, { "name": "Beryl Rice", "gender": "3", "company": "Velity" }, { "name": "Wilder Gonzales", "gender": "4", "company": "Geekko" }, { "name": "Georgina Schultz", "gender": "1", "company": "Suretech" }]
}
]);
You need to apply a cell filter. I've forked your plunkr with a solution.
Filter:
app.filter('mapGender', function() {
var genderHash = {
1: 'male',
2: 'female',
3: 'both',
4: 'none'
};
return function(input) {
if (!input){
return '';
} else {
return genderHash[input];
}
};
});
Column Def:
{
field: 'gender',
editType: 'dropdown',
cellFilter: 'mapGender',
enableCellEdit: true,
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownOptionsArray: $scope.genderTypes,
editDropdownIdLabel: 'ID',
editDropdownValueLabel: 'type'
}
Plunker: http://plnkr.co/edit/hnaMJjBGaQgMGcgt3Hc2?p=preview
References:
Custom UI-Grid Filters: http://ui-grid.info/docs/#/tutorial/306_custom_filters
Angular Filter: https://docs.angularjs.org/api/ng/filter/filter
I created a comboBox and when I select a value, no value will be displayed.
Ext.create("Ext.form.field.ComboBox", {
name: el.name,
fieldLabel: el.labelId,
hidden: !(el.visible),
displayField:"value",
valueField:"value",
flex: 1,
store:Ext.create("Ext.data.Store",{
fields: ['key', 'value'],
data: [
{ key: "10",value: "etap 0"},
{ key: "200",value: "etape 1"},
{ key: "300", value: "etape 3"}
]
}),
regex: el.parameterType.regex,
regexText: el.regExErrMsg,
allowBlank: !el.mandatory,
blankText: el.requiredErrMsg
})
EDIT
Here is exactly the method that return combo:
drawField: function (el) {
var me = this;
var uiField = Ext.create(me.componentType, {
name: el.name,
fieldLabel: el.labelId,
hidden: !(el.visible),
flex: 1,
regex: el.parameterType.regex,
regexText: el.regExErrMsg,
allowBlank: !el.mandatory,
blankText: el.requiredErrMsg
});
if (el.parameterType.isCombo) {
uiField.displayField = 'value';
uiField.valueField = 'key';
uiField.editable = false;
uiField.store = Ext.create('Ext.data.Store', {
fields: ['key', 'value'],
data: el.parameterType.values
});
}
return uiField;
}
and el parameter is a JavaScript object like that:
{
name: "",
labelId: "Champ :",
parameterType: {
regEx: "^.*$",
errID: "115",
isCombo: true,
values:[
{key: "10", value: "etap 0"},
{key: "200",value: "etape 1"},
{key: "300",value: "etape 3"},
],
selectedValue: "etap 0"
},
mandatory: false,
visible: true,
defaultValue: "",
elementType: "LIST_BOX",
regExErrMsg: "Valeur invalide.",
requiredErrMsg: ""
}
and me.componentType at runtime is Ext.form.field.ComboBox
This fiddle works fine for me, I removed the references to el as it shown undefined for me and also changed Ext.data.store to Ext.data.Store
https://fiddle.sencha.com/#fiddle/jj6
Ext.application({
name: 'Fiddle',
launch: function() {
Ext.create("Ext.form.field.ComboBox", {
renderTo: Ext.getBody(),
displayField: "value",
valueField: "value",
flex: 1,
store: Ext.create("Ext.data.Store", {
fields: ['key', 'value'],
data: [{
key: "10",
value: "etap 0"
}, {
key: "200",
value: "etape 1"
}, {
key: "300",
value: "etape 3"
}]
})
});
}
});
valueField:"value" is wrong, you should specify valueField:"key" in order for ComboBox to work properly
I am using this multiselect feature
http://docs-origin.sencha.com/extjs/4.2.2/#!/api/Ext.form.field.ComboBox-cfg-multiSelect
It works ok and i can select multiple values. But the search as you type only works for the first entry , it don't work for next entry
I want like we selects tags in Stackoverflow question
There is problem with raw ComboBox - it synchronizes selection with value list on picker. To have behaviour as described, you should extend it or find another component.
Below is a example extension, which is not perfect, but may be used as a start point:
Ext.define('Ext.form.field.MultiComboBox', {
extend: 'Ext.form.field.ComboBox',
initComponent: function() {
this.displayTpl = new Ext.XTemplate(
'<tpl for=".">' +
'<tpl if="xindex == xcount">{[typeof values === "string" ? values : values["' + this.displayField + '"]]}</tpl>' +
'</tpl>'
);
this.tpl = Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<div class="x-boundlist-item x-boundlist-item-no-selection">{' + this.displayField + '}</div>',
'</tpl>'
);
this.multiSelect = true;
this.selection = [];
this.callParent();
},
// when tag is added or removed, this sets size for table cell
adjustSelectedWidth: function() {
var me = this,
cell = me.selectedCell,
width = 0;
cell.select('span.tag').each(function(el) {
width += el.getWidth() + el.getMargin('lr');
});
cell.setWidth(width);
},
// creates table cell for tags, and attaches click handler
afterRender: function(){
var me = this;
me.callParent(arguments);
var triggerWrap = me.triggerWrap,
tr = triggerWrap.down('tr');
// create table cell
me.selectedCell = tr.createChild({
tag: 'td',
cls: Ext.baseCSSPrefix + 'selected-cell'
}, tr.child('td'));
// attach click handler
me.mon(me.selectedCell, {
click: me.onSelectedCellClick,
scope: me
});
me.addChildEls({ name: 'selectedCell', select: '.' + Ext.baseCSSPrefix + 'selected-cell' });
},
// handle click on list
onItemClick: function(picker, record) {
var me = this,
cell = me.selectedCell,
value = record.get(me.valueField),
display = record.get(me.displayField);
if (me.selection.indexOf(record) === -1) {
// TODO: make template
// store selection
me.selection.push(record);
// create element which displays tag
me.selectedCell.createChild({
tag: 'span',
html: display + '<span class="remove-tag"></span>',
cls: 'tag tag-' + value,
recordValue: value
});
}
// adjust width
me.adjustSelectedWidth();
},
onSelectedCellClick: function(event) {
var me = this,
targetEl = event.getTarget('.remove-tag', null),
tagEl = targetEl.parentNode,
match = tagEl && tagEl.className.match(/tag/);
if (match) {
tagEl = Ext.get(tagEl);
var value = tagEl.getAttribute('recordValue');
var index = -1;
// remove value from selection
me.selection = me.selection.filter(function(element, index, array) {
return element.get(me.valueField) != value;
}, me);
// remove element which displays tag
tagEl.remove();
// adjust width
me.adjustSelectedWidth();
}
},
// return value based on selection stored in combo instead of selection model
getValue: function() {
var me = this,
sel = me.selection,
value = '';
for (var i = 0; i < sel.length; ++i) {
value += (i === 0 ? '' : me.delimiter) + sel[i].get(me.valueField);
}
return value;
}
});
Ext.onReady(function() {
Ext.define('Tag', {
extend: 'Ext.data.Model',
fields: [
{name: 'name', type: 'string'}
]
});
var data = {
tags: [
{ name: '00' },{ name: '01' },{ name: '02' },{ name: '03' },{ name: '04' },{ name: '05' },{ name: '06' },{ name: '07' },{ name: '08' },{ name: '09' },
{ name: '10' },{ name: '11' },{ name: '12' },{ name: '13' },{ name: '14' },{ name: '15' },{ name: '16' },{ name: '17' },{ name: '18' },{ name: '19' },
{ name: '20' },{ name: '21' },{ name: '22' },{ name: '23' },{ name: '24' },{ name: '25' },{ name: '26' },{ name: '27' },{ name: '28' },{ name: '29' },
{ name: '30' },{ name: '31' },{ name: '32' },{ name: '33' },{ name: '34' },{ name: '35' },{ name: '36' },{ name: '37' },{ name: '38' },{ name: '39' }
]
};
//note how we set the 'root' in the reader to match the data structure above
var store = Ext.create('Ext.data.Store', {
autoLoad: true,
model: 'Tag',
data : data,
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'tags'
}
}
});
Ext.create('Ext.form.Panel', {
renderTo: 'form',
items: [
Ext.create('Ext.form.field.MultiComboBox', {
store: store,
displayField: 'name',
valueField: 'name',
queryMode: 'local',
width: 400
})
]
});
});
Working sample: http://jsfiddle.net/f2JuX/16/
I have a problem with store.sync()
I use multiple form (multiple instance of same model in different tab) with the same model/store but with not all the fields of the model.
When i use store.sync the store work, i have the record in my database and the result is success:true !
I load the form :
if(modeleActif == 'UniteDeTemps') {
var form = Ext.getCmp('Form'+modeleActif+'1');
var record = Ext.create('ModuleGestion.model.'+modeleActif);
form.loadRecord(record);
var form = Ext.getCmp('Form'+modeleActif+'2');
var record = Ext.create('ModuleGestion.model.'+modeleActif);
form.loadRecord(record);
var form = Ext.getCmp('Form'+modeleActif+'3');
var record = Ext.create('ModuleGestion.model.'+modeleActif);
form.loadRecord(record);
var form = Ext.getCmp('Form'+modeleActif+'4');
var record = Ext.create('ModuleGestion.model.'+modeleActif);
form.loadRecord(record);
}
My controller action:
if(modeleActif == 'UniteDeTemps') {
modeleUDTActif = Ext.getCmp('TabUniteDeTempsForm').getActiveTab().id;
Type_O_J_S_M = modeleUDTActif.substr(15,modeleActif.length);
var form = Ext.getCmp('Form'+modeleActif+Type_O_J_S_M);
var store = this['get'+modeleActif+'Store']();
record = form.getRecord();
values = form.getValues();
if (form.isValid()) {
record.set(values);
store.add(record);
store.sync({
success: function(batch, options) {
store.load();
},
failure: function(batch, options) {
Ext.Msg.alert("Erreur",batch.proxy.getReader().jsonData.message);
}
});
}
}
My model
Ext.define('ModuleGestion.model.UniteDeTemps', {
extend: 'Ext.data.Model',
idProperty: 'idUniteDeTemps',
fields: [
{
name: 'idUniteDeTemps'
},
{
name: 'UniteDeTemps'
},
{
name: 'Type_O_J_S_M'
},
{
name: 'Type_M'
},
{
name: 'Occurence'
},
{
name: 'RepetitionJ'
},
{
name: 'RepetitionS'
},
{
name: 'Jours'
},
{
name: 'Mois'
},
{
name: 'Quantieme'
},
{
name: 'Numero'
}
]
});
My form:
{
xtype: 'form',
border: false,
id: 'FormUniteDeTemps1',
bodyPadding: 10,
title: '',
items: [
{
xtype: 'textfield',
width: 305,
fieldLabel: 'Nom',
name: 'UniteDeTemps'
},
{
xtype: 'hiddenfield',
fieldLabel: 'Label',
name: 'idUniteDeTemps'
},
{
xtype: 'hiddenfield',
fieldLabel: 'Label',
name: 'Type_O_J_S_M'
},
{
xtype: 'numberfield',
fieldLabel: 'Nombre d\'occurences',
labelWidth: 150,
name: 'Occurence'
}
]
}