I'm trying to make grouped filters for KendoUI grid. I have to create a text field that filters the grid by name and a kendo numeric field that filters grid by Units in stock.
How could I make grouped filters?
I tried the following but it's not working - bad request 404 error:
$('body').bind('keyup mouseup', '#UnitsInStock', function () {
var value = $('#UnitsInStock').val();
var val = $('#ProductName').val();
if (value) {
grid.data("kendoGrid").dataSource.filter(myFilters(val, value));
} else {
grid.data("kendoGrid").dataSource.filter();
}
});
function myFilters(name='', price='') {
var filters = {
logic: "or",
filters: [
{ field: "ProductName", operator: "startswith", value: name},
{ field: "UnitsInStock", operator: "gte", value: price}
]
}
return filters;
}
<div id="grid"></div>
<script type="text/x-kendo-template" id="template">
<div class="toolbar">
<label for="category">Search by Product Name:</label>
<input type="search" id="ProductName" />
<input id="UnitsInStock" type="number" />
</div>
</script>
Since you have fields to be filtered on of multiple types, make sure the types are preserved when creating the filter object. for example, you could predefined your filter fields as such..
var filterFields = [{ field: "Units", type: "number" }, { field: "Name", type: "string" }]
and get the user input
var searchString = // user input
and a method to generate the filters similar to this
var getFilter = function (filterFields, searchString) {
var filterInt = function (value) {
if (/^(\-|\+)?([0-9]+|Infinity)$/.test(value))
return true;
return false;
}
var filters = [];
var i = 0;
for (var i = 0; i < filterFields.length; i++) {
if (filterFields[i].type === "string") {
filters.push({
field: filterFields[i].field,
operator: "startswith",
value: searchString.toString()
});
}
if (filterFields[i].type === "number") {
if (filterInt(searchString)) {
filters.push({
field: filterFields[i].field,
operator: "gte",
value: parseInt(searchString)
});
}
}
}
return {
logic: "or",
filters: filters
};
}
finally, filter your grid
grid.data("kendoGrid").dataSource.filter(getFilter(filterFields, searchString))
also, to be certain that your endpoint works, use a tool such as postman and do a GET (http://............./Units?$filter=Id eq 1 and Name eq 'name').
Related
I am having an error that my obj.push() and obj.concat() is not a function but I am not so sure why. Here is my code:
onSearch = () => {
var obj = {
product: [
{
field: "is_published",
filter_value: 1
},
{
field: "order_mode",
filter_array: [
"fcfs",
"purchase-order"
]
},
{
relationship: "store",
filter_object: {
field: "slug",
filter_value: "sample"
}
}
]
}
if (this.state.search !== "") {
obj.push(
{
field: "name",
text_search: this.state.search
}
)
}
var obj2 = {
taxonomies: [
[
{ field: "type",
filter_value: "seller"
},
{ field: "slug",
filter_value: "brand"
}
]
]
}
var conc = obj.concat(obj2);
var { getProductSearch } = this.props
getProductSearch(obj.concat(obj2))
}
product and taxonomies are stored in different variables but I need to pass them as one array to getProductSearch and for that, I need to use concat(). then I need to use push() because I want to add an object to the array obj. What am I doing wrong?
The simple answer is because you can't push onto an object. Push is used for arrays.
To make this work you could instead change your code to push onto the array in your object by doing.
obj.product.push(
{
field: "name",
text_search: this.state.search
}
)
If you are trying to make product dynamic where there are multiple products like [fruits, veggies, meat] then you could change it simply by doing
onSearch(productName)
obj[productName].push(
{
field: "name",
text_search: this.state.search
}
)
This would let you call onSearch(veggies) and push only to that array if you set it up that way.
I have a page that provides the user 5 dropdown lists with Security Questions. They are set via a local DataSource object, that is basically 10 questions in an object. I want to bind all 5 dropdown lists to the same DataSource, and one Question is selected, remove it from the DataSource, so you can't select it for any of the next questions. Here is my code so far:
var questions =
[{
value: "Your first pet\'s name?"
},
{
value: "Your favorite teacher?"
},
{
value: "The city you were born in?"
},
{
value: "Your mother\'s maiden name?"
},
{
value: "The high school you attended?"
},
{
value: "First name of the first person you kissed?"
},
{
value: "What did you want to be when you grow up?"
},
{
value: "The brand of your first car?"
},
{
value: "Your favorite city?"
}];
var localDataSource = new kendo.data.DataSource({
data: questions
});
var dropdown = $('.dropdownlist');
dropdown.kendoDropDownList({
dataTextField: "value",
dataValueField: "value",
dataSource: localDataSource
});
And my HTML to render the fields:
<input class="dropdownlist w250px" name="questions[1][question]" />
Times 5 for every question.
To achieve the desired behavior, you can use the same data, but separate DataSource instances, otherwise you will not be able to filter them differently for each DropDownList.
Here is an example that you can use as a starting point and customize it further to match your scenario.
http://dojo.telerik.com/aJeHa
Used APIs include:
DropDownList change event
DropDownList value method
DropDownList dataSource field
DataSource filter method
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Related Kendo UI DropDownLists</title>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1118/styles/kendo.common.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1118/styles/kendo.default.min.css">
<script src="http://code.jquery.com/jquery-1.12.3.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.3.1118/js/kendo.all.min.js"></script>
</head>
<body>
<p><input id="ddl1" name="ddl1" class="related-dropdown" /></p>
<p><input id="ddl2" name="ddl2" class="related-dropdown" /></p>
<p><input id="ddl3" name="ddl3" class="related-dropdown" /></p>
<script>
var data = [
{ id: 1, text: "question 1" },
{ id: 2, text: "question 2" },
{ id: 3, text: "question 3" }
];
for (var j = 1; j <= data.length; j++) {
$("#ddl" + j).kendoDropDownList({
dataSource: {
data: data,
filter: {}
},
dataTextField: "text",
dataValueField: "id",
optionLabel: "Select a question",
change: onChange
});
}
function onChange(e) {
if (e.sender.value()) {
var otherDropDowns = $("input.related-dropdown").not(e.sender.element);
for (var j = 0; j < otherDropDowns.length; j++) {
var ddl = $(otherDropDowns[j]).data("kendoDropDownList");
var newCondition = { field: "id", operator: "neq", value: e.sender.value() };
var currentFilter = ddl.dataSource.filter();
if (currentFilter && currentFilter.filters) {
currentFilter.filters.push(newCondition);
ddl.dataSource.filter(currentFilter);
} else {
ddl.dataSource.filter(newCondition);
}
}
} else {
// clear the freed question from the DropDownLists' filter criteria
}
}
</script>
</body>
</html>
I am using ui-grid to show a list of data and on display of the grid I am trying to expand some of the rows depending on the data.
I am trying to do this in the onRegisterApi event:
scope.GridOptions = {
data: properties,
columnDefs:
[
{ name: "Full Address", field: "FullAddress" },
{ name: "Suburb", field: "Suburb" },
{ name: "Property Type", field: "PropertyType" },
{ name: "Price", field: "Price", cellFilter: 'currency'},
{ name: "Status", field: "Status" },
{ name: "Sale Type", field: "SaleType" },
{ name: "Date Created", field: "CreateDate", cellFilter: "date:'dd/MM/yyyy HH:mma'"}
],
expandableRowTemplate: 'template.html',
expandableRowHeight: 200,
onRegisterApi: (gridApi) =>
{
gridApi.expandable.expandAllRows();
}
};
The problem is gridApi.expandable.expandAllRows() expands all of the grouped sections. I see there is a expandRow function, but I am not sure how to use it in place of the expandAllRows function. I really would like to expand the group that has the column Status set to a particular value. Can someone help me figure this out?
Here is a way to handle expanding of selective rows. I have created a Plunker link (http://plnkr.co/edit/CSaROQqKxYnkoxm2Tl6b?p=preview) where I am expanding all the even rows. In a similar way, you can iterate over the array and expand the required rows.
Include:
"$timeout" dependency in the controller
To expand first row:
$timeout(function() {
var rows = $scope.gridApi.grid.rows;
var entity = (rows.length && rows[0]) ? rows[0].entity : null;
$scope.gridApi.expandable.toggleRowExpansion(entity);
});
May be I am late to answer.
But it may help others.
I have taken the same plunker example as SaiGiridhar posted, but modified
$timeout(function() {
var rows = $scope.gridApi.grid.rows;
for(var i=0; i < rows.length; i++){
if(i%2 === 0){
var entity = (rows.length && rows[i]) ? rows[i].entity : null;
$scope.gridApi.expandable.toggleRowExpansion(entity);
}
}
});
to
$scope.$$postDigest(function() {
var rows = $scope.gridApi.grid.rows;
for(var i=0; i < rows.length; i++){
if(i%2 === 0){
var entity = (rows.length && rows[i]) ? rows[i].entity : null;
$scope.gridApi.expandable.toggleRowExpansion(entity);
}
}
});
I am currently having problems binding data to an observable array in knockoutJS. What I am trying to do is display new values based on the user's selection from a select box.
The fiddle is available at http://jsfiddle.net/jwayne2978/k0coh1fz/3/
My HTML looks like the following.
<select data-bind="options: categories,
optionsText: 'name',
optionsValue: 'id',
value: selectedCategory,
optionsCaption: 'Choose...',
event: { change: categoryChanged }
">
<div data-bind="foreach: values">
<div data-bind="text: name"></div>
</div>
<div data-bind="foreach: categories">
<div data-bind="text: name"></div>
</div>
My JavaScript looks like the following.
var categories = [
{ "name" : "color", "id": "1" },
{ "name" : "names", "id": "2" }
];
var values0 = [ { "name" : "empty1" }, { "name" : "empty2" } ];
var values1 = [ { "name" : "white" }, { "name" : "black" } ];
var values2 = [ { "name" : "john" }, { "name" : "name" } ];
var Category = function(data) {
this.name = ko.observable(data.name);
this.id = ko.observable(data.id);
};
var Value = function(data) {
this.name = ko.observable(data.name);
}
var ViewModel = function(categories, values) {
var self = this;
self.categories = ko.observableArray(ko.utils.arrayMap(categories, function(category) {
return new Category(category);
}));
self.selectedCategory = ko.observable();
self.values = ko.observableArray(ko.utils.arrayMap(values, function(value) {
return new Value(value);
}));
self.categoryChanged = function(obj, event) {
if(self.selectedCategory()) {
console.log(self.selectedCategory());
if("1" == self.selectedCategory()) {
//console.log(values1);
self.values.push(new Value({"name":"test1"}));
} else if("2" == self.selectedCategory()) {
//console.log(values2);
self.values.push(new Value({"name":"test2"}));
}
}
};
};
var viewModel;
$(document).ready(function() {
viewModel = new ViewModel(categories, values0);
ko.applyBindings(viewModel);
});
When a category is changed, what I really want to do is something like this.
self.values.removeAll();
for(var v in values1) {
self.values.push(new Value(v));
}
But that doesn't work and so I simply have the line to push a new value into the observable array.
Also, my iterations on the div for the values and categories are not showing and I am unsure why.
Any idea on what I am doing wrong?
your <select> element is missing a closing tag and causing issues further down in the view.
<select data-bind="options: categories,
optionsText: 'name',
optionsValue: 'id',
value: selectedCategory,
optionsCaption: 'Choose...',
event: { change: categoryChanged }"></select>
updated fiddle: http://jsfiddle.net/ragnarok56/69q8xmrp/
I want to assign ng-grid columns name dynamically after value returned from database, but issue is that it get initialized before data return from ajax, and i am not able to recall gridOption so it showing balnk, so please help me that how can we construct a column name by ajax return value.
$scope.gridOptions =
{
data: 'data.Values',
columnDefs:
[
{ field: "ID", displayName: "Record Id" },
{ field: "Value", displayName: $scope.ColumnName, cellFilter: cellfilterType },
],
};
where $scope.ColumnName coming from below line...
RecordService.getRecords().then(function (data) {
$scope.ColumnName= data.something;
}
Thanks
Thanks Max for your help, I have done this with of help columnDef as below:
Step 1:
$scope.colDef = [];
Step 2:
RecordService.getRecords().then(function (data){
$scope.colDef=["ColumnName":data.something]
}
Step 3:
$scope.gridOptions = {
data: 'data.UdiValues',
columnDefs:'colDef',
filterOptions: $scope.filterOptions
};
Try to set first "default" value and after change it with promise
$scope.gridOptions =
{
data: 'data.Values',
columnDefs:
[
{
field: "ID",
displayName: "Record Id"
},
{ field: "Value",
displayName: "default",
cellFilter: cellfilterType
},
]
};
And now:
RecordService.getRecords().then(function (data) {
$scope.gridOptions.columnDefs[1].displayName = data.something;
}
The Service RecordService returns promise therefore we create promise factory like:
.factory('RecordService', ['$resource','$q', function($resource, $q) {
var data = { something: "from service" } ;
var factory = {
getRecords: function (selectedSubject) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
}]);
Demo Fiddle
Something like this
Return json, play around, use GET mapping to strings etc?
i have done something like this :-
self.gridOptions.columnDefs = columnDefs(colDef,displayNames);
columnDef is :-
var columnDefs = function(data,cd){
var colDef= [];
var mi = null;
var colByOrder = sortedByOrder(data);
for(var i=0 ; i < colByOrder.length ; i++){
colDef.push({
width: width,
field: String(colByOrder[i][1].position),
menuItems: menuItems(this),
displayName: cd[colByOrder[i][1].position],
enableSorting: false,
type: 'string',
});
}
return colDef;
};