I have a set of fields or each row looking like
{inBing:true, inOSM:true, inGoogle:false}.
Depending on these I want to represent these values as a string, like 'B O', meaning Bing and OSM are enabled and Google is not.
So I need to go through these fields and build an output string.
The question is where can I put and call this function in UI grid?
I'd use a filter for this.
Manipulate your data to look like:
{ field1: value1, field2: value2, searchFlags: { inBing: true, inOSM: false, inGoogle: true } }
{ field1: value2, field2: value4, searchFlags: { inBing: false, inOSM: true, inGoogle: false } }
...
And your columnDefs like:
columnDefs: [
{ name: 'field1' },
{ name: 'field2' },
{ name: 'searchFlags', cellFilter: 'mapFlags' }
];
Finally, define the filter:
.filter('mapFlags', function( input ) {
str = '';
if (v.inBing) str += 'B ';
if (v.inOSM) str += 'O ';
if (v.inGoogle) str += 'G';
return str;
});
There is an example of a filter in http://ui-grid.info/docs/#/tutorial/201_editable
could use a custom cell template like this:
columnDefs: [
{ name: 'name' },
...
{ name: 'whichSearchEngines', field: 'some_field', cellTemplate: '<div class="ui-grid-cell-contents" >{{grid.appScope.searchEngineFormatter(row.some_field)}}</div>' }
]
$scope.searchEngineFormatter = function (v) {
str = '';
if (v.inBing) str += 'B ';
if (v.inOSM) str += 'O ';
if (v.inGoogle) str += 'G';
return str;
};
Related
My from elements are written in Object. I need to populate HTML form elements from that. Problem is that Object contains different input types, structure, custom rules etc. For example, there will be text input, image type input, select box, radio, checkbox etc. So, I don't understand looping over the object will be good idea (I started this, but couldn't complete by myself :( ). I could write the html tag element in html file too. But, I must take the value from that object. So, what's the best solution for it?
Sample Object:
var formObj = {
username: {
value: null,
type: 'text',
placeholder: 'Enter username'
},
password: {
value: null,
type: 'password',
placeholder: 'enter password'
},
country: {
value: null,
type: 'select',
defaultText: 'Choose here',
option: [
{
value: '1',
label: 'Australia'
},
{
value: '2',
label: 'USA'
},
{
value: '3',
label: 'UK'
}
]
},
gender: {
value: null,
type: 'select',
defaultText: null,
option: [
{
value: 'male',
label: 'Male'
},
{
value: 'female',
label: 'Female'
},
{
value: 'other',
label: 'Other'
}
]
}
}
jsfiddle demo
your jsfiddle demo revised
Added some comments to your demo. I'd also look into template strings. They'll make your life easier and code cleaner :) and the single responsibility principle for breaking your code into easier to manage/read pieces.
var html = ''; // <-- Initialize as empty string for `+=`
$.each(formObj, function(key, value) {
if (value.value === null) {
value.value = '';
}
// Add label
html += '<label for="' + key + '">' + key + '</label>';
// Add input
if (value.type === 'select') {
// Type is select
html += '<select class="form-control">' + generateOptionPlaceholder(value.defaultText) + generateOptionMarkup(value.option) + '</select>';
} else {
html += '<input name="' + key + '" type="' + value.type + '" value="' + value.value + '" placeholder="' + value.placeholder + '" class="form-control" />';
}
console.log(html);
});
You could use a strategy pattern for this sort of thing. For any variance, used a dictionary where the keys are based off of the variant, and the values are a function to call for that variant.
For example, if your object with form data had a structure like this:
var form = {
"field1": {
type: "text"
value: "foo",
attrs: {...}
},
...
}
You can use a strategy to handle different field types. Your strategy dictionary might start our like this:
var FIELD_STRATEGY = {
"input": function (name, value, attrs) {
// General purpose method for <input>
// Needs type included in attrs
"text": function (name, value, attrs) {
// Constructs an <input type="text">
attrs.type = "text";
return FIELD_STRATEGY.input(name, value, attrs);
},
"option": function (value, label, attrs) {
// Constructs an <option>
},
"select": function (name, options, attrs {
// Constructs a <select>
var opts = options.map(function(opt) {
return FIELD_STRATEGY.option(
null,
opt.value,
opt.label);
}).join("");
var attr_str = Object.keys(attrs).map(function(attr) {
var value = attrs[attr];
return name + '="' + value '"';
}).join(" ");
return '<select name="' + name + '" ' + attr_str + '>' +
opts + '</select>';
}
};
To use it, loop over the field names and invoke strategies based on type:
var fields = Object.keys(form).map(function (name) {
var conf = form[name] || {};
var strategy = FIELD_STRATEGY[conf.type];
var rendered = "";
if (strategy) {
rendered = strategy(name, conf.value, conf.attrs);
}
return rendered;
});
This will give you a final fields list containing rendered strings based on the strategy for each field type.
I intend to build a text with the text of labelField and textfield value
In my fiddle example the text of the fieldLabel is created dynamically.
what I want to achieve is to generate a text with the text of fielLabel and the value of the textfield.
https://fiddle.sencha.com/#fiddle/1icj
As is the fiddle displays "Homer, Simpson"
What I want to achieve: "Name Homer, Last Name Simpson"
It seems to me there is no method which gives the value of fieldLabel.
How to achieve this?
It is possible in some way, using binding?
What if I use a custom property, it is possible to obtain its value?
buttons: [{
text: 'GetValues',
handler: function() {
var formValues = this.up('form').getForm().getValues();
console.log(formValues);
var finalValues = [];
var needsLineBreak = false;
if (formValues != null) {
var form=this.up('form'),
index=0;
Ext.iterate(formValues,function(key,val){
finalValues += form.getComponent(index).getFieldLabel()+':';
finalValues += val + ',';
index++;
});
finalValues=finalValues.slice(finalValues.lenght,-1);
}
console.log(finalValues);
}
}],
you can use getter/setter to achieve this functionality
items: [{
fieldLabel: labelName,
name: 'first',
get value(){
return this.fieldLabel +' Homer';
},
allowBlank: false,
myCustomProp: labelName
},{
fieldLabel: labelLastName,
name: 'last',
get value(){
return this.fieldLabel +' Simpson';
},
allowBlank: false
}],
I'm currently struggling with implementing a jQuery plugin to my site for tags (with custom data objects) with autocomplete. jQuery TextExt can be found here (http://textextjs.com/). I'm currently struggling with using custom data objects for each tag, which can only be chosen from what autocompletes. Based on this example (http://textextjs.com/manual/examples/tags-with-custom-data-objects.html) I'm trying to figure out how to return both "name" and "id" when a tag is chosen. Does anyone know how to achieve this or point me in the correct direction?
Perhaps the answer is somewhere in this example (http://textextjs.com/manual/examples/filter-with-suggestions.html)?
Here's what I have written, which isn't working (it only returns the name, I've tried adding 'item.id' to the functions but that didn't work for me either):
<script type="text/javascript">
jQuery(document).ready(function( $ ){
jQuery('#textarea').textext({
plugins: 'tags',
items: [
{ name: 'PHP', id: '1' },
{ name: 'Closure', id: '2' },
{ name: 'Java', id: '3' }
],
ext: {
itemManager: {
stringToItem: function(str)
{
return { name: str };
},
itemToString: function(item)
{
return item.name ;
},
compareItems: function(item1, item2)
{
return item1.name == item2.name;
}
}
}
});
})
</script>
Your itemManager code should probably look like this, you will need to store the suggestions in a custom array to look up their relevant ids in the stringToItem Method
itemManager: {
items: [], // A custom array that will be used to lookup id
stringToItem: function(str)
{
//Lookup id for the given str from our custom array
for (var i=0;i<this.items.length;i++)
if (this.items[i].name == str) {
id = this.items[i].id;
break;
}
return { name: str, id: id };
},
itemToString: function(item)
{
//Push items to our custom object
this.items.push(item);
return item.name ;
},
compareItems: function(item1, item2)
{
return item1.name == item2.name;
}
}
I am working with the ng-grid in Angular js.
I have this line of code which defines the type of filter added.
columnDefs: [{field:'date', displayName:'Birth Date', cellFilter:'date:\"dd MMM yyyy\"'},
{field:'pre', displayName:'Prev', cellFilter:'number'},
{field:'fct', displayName:'Fct', cellFilter:'number'},
{field:'act', displayName:'Act', cellFilter:'number'}
{field:'imp', displayName:'Important', cellFilter:'number'}]
};
the Important column has values "H" "L" and "M". By normal(alphabetical) sorting I can achieve a sort of H-L-M but is there a way to define a filter that sorts as "H-M-L".
Any help is appreciated!! Thanks :)
Use a custom sort function:
var result = 1;
var test="HML";
function impSortFn(a, b) {
a=test.indexOf(a);
b=test.indexOf(b);
if (a == b) return 0;
if (a < b) return -1;
return result;
}
$scope.gridOptions = {
data: 'myData',
columnDefs: [{
field: 'name',
displayName: 'Name'
}, {
field: 'age',
displayName: 'Age'
}, {
field: 'imp',
displayName: 'Important',
sortFn: impSortFn
}]
See this Plunker
I use multi-row grouping and put the totals in the grouping headers.
I'm not using the totals in the totals rows. I see the the rows are grouped and where the totals would be there are empty rows. In my case there is an empty row after each of the child grouping and at the end there is an empty row for the parent totals.
How do I remove these totals rows?
Thank you!
.cshtml:
<div id="gridList" class="grid" style="width: 100%; height: 500px"></div>
.js
$(function() {
var columns = [
{
id: "isExcluded",
name: "Exclude",
field: "isExcluded" /*, width: 120*/,
formatter: Slick.Formatters.Checkmark,
editor: Slick.Editors.Checkbox, sortable: true
},
{
id: "symbol",
name: "Symbol",
field: "symbol",
sortable: true /*, width: 120*/
},
{
id: "price",
name: "Price",
field: "price",
sortable: true
//, groupTotalsFormatter: sumTotalsFormatter
},
{
id: "parent_name",
name: "Parent Name",
field: "parent_name",
sortable: true /*, width: 120*/
},
{
id: "description",
name: "Description",
field: "description",
sortable: true,
width: 120,
editor: Slick.Editors.Text,
},
{ id: "cancel_ind",
name: "Canceled",
field: "cancel_ind",
sortable: true, width: 80 }
];
function requiredFieldValidator(value) {
if (value == null || value == undefined || !value.length) {
return { valid: false, msg: "This is a required field" };
} else {
return { valid: true, msg: null };
}
};
var options = {
editable: true,
enableAddRow: true,
enableCellNavigation: true,
asyncEditorLoading: false,
autoEdit: true,
enableExpandCollapse: true,
rowHeight: 25
};
var sortcol = "parent_name";
var sortdir = 1;
var grid;
var data = [];
var groupItemMetadataProviderTrades = new Slick.Data.GroupItemMetadataProvider();
var dataView = new Slick.Data.DataView({ groupItemMetadataProvider: groupItemMetadataProviderTrades });
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount();
grid.render();
});
dataView.onRowsChanged.subscribe(function (e, args) {
grid.invalidateRows(args.rows);
grid.render();
});
function groupByParentAndSymbol() {
dataViewTrades.setGrouping([
{
getter: "parent_name",
formatter: function(g) {
return "Parent: " + g.value + " <span style='color:green'>(" + g.count + " items) Total: " + g.totals.sum.price + "</span>";
},
aggregators: [
new Slick.Data.Aggregators.Sum("price")
],
aggregateCollapsed: true
,lazyTotalsCalculation: true
},
{
getter: "symbol",
formatter: function(g) {
return "Symbol: " + g.value + " <span style='color:green'>(" + g.count + " items) Total: " + g.totals.sum.price + "</span>";
},
aggregators: [
new Slick.Data.Aggregators.Sum("price")
],
collapsed: true
,lazyTotalsCalculation: true
}]);
};
grid = new Slick.Grid("#gridList", dataView, columns, options);
grid.registerPlugin(groupItemMetadataProviderTrades);
grid.setSelectionModel(new Slick.RowSelectionModel());
..... /*sorting support etc*/
// use instead of the default formatter <--- removed not used.
function sumTotalsFormatter(totals, columnDef) {
var val = totals.sum && totals.sum[columnDef.field];
//if (val != null) {
// return "total: " + ((Math.round(parseFloat(val) * 100) / 100));
//}
return "";
}
// will be called on a button click (I didn't include the code as irrelevant)
var getDataList = function () {
$.getJSON('/Home/GetData/', function (json) {
data = json;
dataView.beginUpdate();
dataView.setItems(data);
groupByParentAndSymbol();
dataView.endUpdate();
dataView.syncGridSelection(grid, true);
});
};
getDataList();
});
Adding displayTOtalsRow: false to the dataview solved my problem - the total rows are not shown now.
var dataView = new Slick.Data.DataView({ groupItemMetadataProvider: groupItemMetadataProviderTrades, displayTotalsRow: false });
To answer simply to your question... Just remove the aggregators: [...], when I say remove you have 2 options, you can remove whatever is the array [...] or you could simply erase completely that object line (so removing completely the aggregators[...]).
Now if you want more explanation of how it works...Let's give you some definition so you'll understand better. An aggregate is a collection of items that are gathered together to form a total quantity. The total in question could be a sum of all the fields, an average or other type of aggregator you might define. So basically it's the action of regrouping by the column you chose and give the calculation result of the group. Alright now how does it work in the case of a SlickGrid? You need to define what kind of Aggregator you want to use (Avg, Sum, etc...) that goes inside your function groupByParentAndSymbol(), defining them will do the calculation BUT unless you attach it to the field, nothing will be displayed, so in the example you found it is very important to attach/bind this groupTotalsFormatter: sumTotalsFormatter to your columns definition, as for example:
...var columns = [{id: "cost", ...width: 90, groupTotalsFormatter: sumTotalsFormatter}, ...];
so let's recap... Once the Aggregator is define new Slick.Data.Aggregators.Sum("cost") it will do the calculation but unless it's bind to the field nothing will be displayed. As an extra option, the aggregateCollapsed (true/false) is to display the sub-total (avg, sum or whatever) inside or outside the group when you collapse.