Is it possible, with BackGrid, to build a custom Cell vía formatter, composing values from hidden columns?
var grid = new Backgrid.Grid({
columns: [
{
name:"half_value_1",
cell:"string",
rendered: false
},
{
name:"half_value_2",
cell:"string",
rendered: false
},
{
name: "composite",
cell: "string",
formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
fromRaw: function (half_value_1, half_value_2) {
return half_value_1 + '/' + half_value_2;
}
})
}],
collection: col
});
Can I get the half_value_1 and half_value_2 inside the fromRaw function?
I think the best way to get the result you want is to use a custom cell rather than a custom formatter. You could do something like this for that particular column:
{
name: "composite",
cell: Backgrid.Cell.extend({
render: function(){
// You have access to the whole model - get values like normal in Backbone
var half_value_1 = this.model.get("half_value_1");
var half_value_2 = this.model.get("half_value_2");
// Put what you want inside the cell (Can use .html if HTML formatting is needed)
this.$el.text( half_value_1 + '/' + half_value_2 );
// MUST do this for the grid to not error out
return this;
}
})
}
That should work perfectly for you - I use it for a handful of grids in my projects. I didn't test this code though, so I may have typos :)
Key
Related
I am doing form validations in Sencha Touch 2.3. My model looks like following.
Ext.define('net.omobio.dialog.dialogcc.model.StockTransferDetails', {
extend: 'Ext.data.Model',
config: {
fields: ['to_msisdn','to_profile_id','transfer_lob','transfer_item_status','transfer_product','transfer_qty','transfer_req_type','transfer_item_type','transfer_pack_type'],
validations: [
{ type: 'presence', field: 'to_msisdn' },
{ type: 'presence', field: 'to_profile_id' },
{ type: 'exclusion', field: 'transfer_lob', list: ['null'] },
{ type: 'exclusion', field: 'transfer_req_type', list: ['null'] },
{ type: 'exclusion', field: 'transfer_item_type', list: ['null'] },
{ type: 'exclusion', field: 'transfer_pack_type', list: ['null'] }
]
}
});
Following is a code segment that I use in my controller to remove validations from hidden form fields but no luck.
var form1 = me.getStockTransferRequestPage();
var model = Ext.create("net.omobio.dialog.dialogcc.model.StockTransferDetails", form1.getValues());
// validate form fields
var errors = model.validate();
if (!errors.isValid()) {
// loop through validation errors and generate a message to the user
errors.each(function (errorObj){
//errorString += errorObj.getField() + " " + errorObj.getMessage();
console.log('7777777777777777777 '+errorObj.getField());
if (!Ext.getCmp(errorObj.getField().toString()).isHidden()) {
var s = Ext.String.format('field[name={0}]',errorObj.getField());
form1.down(s).addCls('invalidField');
}
});
Ext.Msg.alert('','stock_transfer.errors.required_fields_empty');
}
I would be much appreciated if anyone could help me to solve this.
Thank you
so there are multiple ways to achieve this, my preference even though some folks won't like it, but it will always work.
I did the following override to solve this problem, tried my best not to affect the normal flow of validation.the first two overrides have to be added somewhere to your overrides folder, you only have to add them once for the whole app.
Ext.Define('Ext.form.field.BaseOverride', {
override: 'Ext.form.field,Base',
/* traverse up and look for a hidden Parent/Ancestor */
isParentHidden: function () {
return this.up('[hidden=true]');
}
/* override isValid basic method to consider skipValidateWhenHidden property, when skipValidateWhenHidden is set to true code should check if the elementor it's Parent/Ancestors is hidden */
isValid: function () {
var me = this,
disabled = me.disabled,
isHidden = me.isHidden(),
skipValidateWhenHidden = !!me.skipValidateWhenHidden,
validate = me.forceValidation || !disabled,
isValid = validate ? me.validateValue(me.processRawValue(me.getRawValue())) : disabled;
if (isValid || !skipValidateWhenHidden) {
return isValid;
}
if (skipValidateWhenHidden) {
isHidden = isHidden ? true : me.isParentHidden();
if (isHidden) {
return skipValidateWhenHidden;
}
}
return isValid;
}
});
and eventually you'll be able to do the following, which is set the property to true on any field so if its not visible for the user, it will survive validation
{
itemId: 'City',
cls: 'AddressCity',
xtype: 'textfield',
emptyText: emptyCityText,
skipValidateWhenHidden: true,
},
another approach is to add a show()/Hide() listener on the fields container to enable/disable the children, disabling the fields would make them skip validation, but i'm not a big fan of managing button states and wiring listeners.
Note
Ext.getCmp() takes component id
errorObj.getField().toString() returns model field name, It won't
return id of the component (hidden) field.
So if model field name matches with hidden field id, It will work. Otherwise it won't work.
I'm using the new Angular UI Grid (that is planned to replace ng-grid).
My data needs some formatting before it's displayed in the table. For instance, my server returns an attribute named "status" as a number, but I want to display it as a nice name.
If status=1 display "Todo", if status=2 display "Doing" etc.
How can this be done in UI Grid?
The preferred method now is to use a cellFilter, rather than a custom template. Custom templates are OK, but they impose more workload on upgrade - you have to check whether new features require modifications to your template.
There is a reasonable example of filters in the tutorials: http://ui-grid.info/docs/#/tutorial/201_editable
Note the cellFilter: 'mapGender' on the gender column, and the filter itself defined further below in the tutorial:
.filter('mapGender', function() {
var genderHash = {
1: 'male',
2: 'female'
};
return function(input) {
if (!input){
return '';
} else {
return genderHash[input];
}
};
})
First step, add a cellTemplate to the column:
$scope.gridOptions.columnDefs = [
{field:'status', displayName: 'Status',cellTemplate: 'statusTemplate.html'}
];
The Template-File should look like this (COL_FIELD is the actual field):
<div style="text-align: center">{{COL_FIELD==1 ? 'Todo' : 'Doing'"}}</div>
Hope, you got the idea! :)
The shortest way is use CellTemplate with appScopeProvider:
vm.gridOptions = {
columnDefs: [
{
field: 'status',
cellTemplate: '<div>{{grid.appScope.formatStatus(row)}</div>'
}
],
appScopeProvider: {
formatStatus: function (row) {
return row.entity.status === 1 ? 'Todo' : 'Doing';
},
}
}
I am new to Ext Js so forgive me if my terminology for certain things is not correct. What I need is text counter. Here is what I have so far...
http://jsfiddle.net/gfrobenius/WxNDf/1/
What I need to do is make this code reusable so that all textareas get this feature but I still have the ability to change the normal settings like label, name, id, maxLength, etc... Does this mean turning it into a class, plugIn, component (sorry still trying to learn terminology)? Can my afterLabelTextTpl be done simpler? I've seen examples like:
var tpl = new Ext.Template('Name: {name}, Age: {age}');
tpl.apply({name: 'John', age: 25});
in the documentation but am not sure how to incorporate it into my code. Also in my three functions for updating the text count you can see I have the line for getting the component hard-coded to 'gtext' and the line for getting the 'countDownSpan' hard-coded as well. How do I go about making them just know the parent item?
You can make your own component and extend from a textarea. Also you're doing 3 times the same thing in your callback function. And the id of your textarea should be unique.
Here's an example of your component:
Ext.define('MyApp.ux.form.field.TextArea', {
alias: 'widget.textareacounter',
extend: 'Ext.form.field.TextArea',
labelAlign: 'top',
enableKeyEvents: true,
enforceMaxLength: false,
maxLength: 1000,
constructor: function(config) {
var me = this;
Ext.apply(me, config);
me.afterLabelTextTpl = ['<span style="margin-left:5px;">(' + me.maxLength + ' char. left)</span>'];
me.callParent()
},
initComponent: function () {
var me = this;
me.on({
keydown: me.calculateCharsLeft,
keyup: me.calculateCharsLeft,
afterrender: me.calculateCharsLeft,
scope: me
});
me.callParent();
},
calculateCharsLeft: function (textfield, e) {
var me = this;
var span = Ext.dom.Query.select('span', me.getEl().dom)[0];
var remaining = me.maxLength - me.getValue().length;
span.innerHTML = '(' + remaining + ' char. left)';
}
});
And a working fiddle: http://jsfiddle.net/johanhaest/cpLvK/2/
I am using backgrid.js with backbone.js. I'm trying to populate JSON (user list) in backgrid. Below is my JSON,
[{"name": "kumnar", "emailId":"kumar#xxx.com",
"locations":{"name":"ABC Inc.,", "province":"CA"}
}]
I can access name & emailId as below,
var User = Backbone.Model.extend({});
var User = Backbone.Collection.extend({
model: User,
url: 'https://localhost:8181/server/rest/user',
});
var users = new User();
var columns = [{
name: "loginId",
label: "Name",
cell: "string"
}, {
name: "emailId",
label: "E-mail Id",
cell: "string"
}
];
var grid = new Backgrid.Grid({
columns: columns,
collection: users
});
$("#grid-result").append(grid.render().$el);
userEntities.fetch();
My question is, how do I add a column for showing locations.name?
I have specified locations.name in the name property of columns but it doesn't work.
{
name: "locations.name",
label: "E-mail Id",
cell: "string"
}
Thanks
Both backbone and backgrid currently don't offer any support for nested model attributes, although there are a number of tickets underway. To properly display the locations info, you can either turn the locations object into a string on the server and use a string cell in backgrid, or you can attempt to supply your own cell implementation for the locations column.
Also, you may try out backbone-deep-model as it seems to support the path syntax you are looking for. I haven't tried it before, but if it works, you can just create 2 string columns called location.name and location.province respectively.
It's really easy to extend Cell (or any of the existing extensions like StringCell). Here's a start for you:
var DeepstringCell = Backgrid.DeepstringCell = StringCell.extend({
render: function () {
this.$el.empty();
var modelDepth = this.column.get("name").split(".");
var lastValue = this.model;
for (var i = 0;i<modelDepth.length;i++) {
lastValue = lastValue.get(modelDepth[i]);
}
this.$el.text(this.formatter.fromRaw(lastValue));
this.delegateEvents();
return this;
},
});
In this example you'd use "deepstring" instead of "string" for your "cell" attribute of your column. Extend it further to use a different formatter (like EmailFormatter) if you want to reuse the built-in formatters along with the deep model support. That's what I've done and it works great. Even better is to override the Cell definitions to look for a "." in the name value and treat it as a deep model.
Mind you, this only works because I use backbone-relational which returns Model instances from "get" calls.
I have a working sort-able grid using the ext 3.4 grid filter plugin. I would like to default the active column to filter true values. User who needs the inactive records could remove the filter. How do I specify a default filter column and value?
Thanks in advance!
colModel: new Ext.grid.ColumnModel({
defaults: {
sortable: true
// How do I specify a default filter value
//
// Only show active records unless the user changes the filter...
},
columns: [{
dataIndex:'f_uid',
id:'f_uid',
header:'ID',
hidden:true
}, {
dataIndex:'f_name',
id:'f_name',
header:'Name',
}, {
xtype:'booleancolumn',
dataIndex:'f_active',
id:'f_active',
header:'Active',
filterable:true,
trueText:'Active',
falseText:'Inactive'
}]
I realise this is an old question but it took me a while to find a solution, therefore I thought I would share.
1) The filter can be set using the value property in the filter.
filter: {
type: 'LIST',
value: ['VALUE TO FILTER']
}
2) In order to initially filter the data use the filterBy() method in the store. This could be defined in the onRender event handler.
this.getStore().load({
scope:this,
callback: function() {
// filter the store
this.getStore().filterBy(function(record, id) {
// true will display the record, false will not
return record.data.DATA_TO_FILTER == 'VALUE TO FILTER ';
});
}
});
The answer was in the Filter.js source code. The filter object within the column definition can be used to configure the default behavior.
}, {
xtype:'booleancolumn',
dataIndex:'f_active',
id:'f_active',
header:'Active',
trueText:'Active',
falseText:'Inactive',
filterable:true,
filter: {
value:1, // 0 is false, 1 is true
active:true // turn on the filter
}
}
I have encountered the same problem and I found that #John's answer is right, I can make it work with the sample http://dev.sencha.com/deploy/ext-4.0.0/examples/grid-filtering/grid-filter-local.html, for the grid-filter-local.js, just add the code like:
grid.getStore().load({
scope:this,
callback: function() {
// filter the store
grid.getStore().filterBy(function(record, id) {
// true will display the record, false will not
return record.data.size === 'small';
});
}
});
before the original code store.load(), and wipe off the store.load().
Then it will only show the record with size equals 'small' at the first load of the web page. Cheers!
I've made a universal helper class that allows you to set any default values in column definition.
https://gist.github.com/Eccenux/ea7332159d5c54823ad7
This should work with both remote and static stores. Note that this also works with filterbar plugin.
So your column item is something like:
{
header: 'Filename',
dataIndex: 'fileName',
filter: {
type: 'string',
// filename that starts with current year
value: Ext.Date.format(new Date(), 'Y'),
active:true
}
},
And then in your window component you just add something like:
initComponent: function() {
this.callParent();
// apply default filters from grid to store
var grid = this.down('grid');
var defaultFilters = Ext.create('Ext.ux.grid.DefaultFilters');
defaultFilters.apply(grid);
},