Sorting array declared in Kendoui Observable - kendo-ui

I have declared an content array in my kendoui observable but how do i sort it in the add function. Here's my code.
var cart = kendo.observable({
contents: [],
cleared: false,
contentsCount: function () {
return this.get("contents").length;
},
isEmpty: function () {
return (this.get("contents").length == 0);
},
add: function (item) {
var found = false;
this.set("cleared", false);
for (var i = 0; i < this.contents.length; i++) {
var current = this.contents[i];
if (current.item.id == item.id) {
current.set("quantity", current.get("quantity") + 1);
found = true;
break;
}
}
if (!found) {
this.contents.push({ item: item, quantity: 1 });
}
// I NEED TO SORT THE ARRAY HERE.
},
});

Related

Vue - DOM is not updating when doing .sort() on array

I am trying to sort some JSON data using Vue. The data gets changed when checking via Vue console debugger, but the actual DOM doesn't get updated.
This is my Vue code:
Array.prototype.unique = function () {
return this.filter(function (value, index, self) {
return self.indexOf(value) === index;
});
};
if (!Array.prototype.last) {
Array.prototype.last = function () {
return this[this.length - 1];
};
};
var vm = new Vue({
el: "#streetleague-news",
data: {
allItems: [],
itemTypes: [],
itemTypesWithHeading: [],
selectedType: "All",
isActive: false,
sortDirection: "newFirst",
paginate: ['sortedItems']
},
created() {
axios.get("/umbraco/api/NewsLibraryApi/getall")
.then(response => {
// JSON responses are automatically parsed.
this.allItems = response.data;
this.itemTypes = this.allItems.filter(function (x) {
return x.Tag != null && x.Tag.length;
}).map(function (x) {
return x.Tag;
}).unique();
});
},
computed: {
isAllActive() {
return this.selectedType === "All";
},
filteredItems: function () {
var _this = this;
return _this.allItems.filter(function (x) {
return _this.selectedType === "All" || x.Tag === _this.selectedType;
});
},
sortedItems: function () {
var _this = this;
var news = _this.filteredItems;
if (_this.sortDirection === 'newFirst') {
news.sort(function (a, b) {
return new Date(b.PostDate) - new Date(a.PostDate);
});
} else {
news.sort(function (a, b) {
return new Date(a.PostDate) - new Date(b.PostDate);
});
}
return news;
}
},
methods: {
onChangePage(sortedItems) {
// update page of items
this.sortedItems = sortedItems;
}
}
});
This is an HTML part:
<paginate class="grid-3 flex" name="sortedItems" :list="sortedItems" :per="12" ref="paginator">
<li class="flex" v-for="item in paginated('sortedItems')">
The bit that seems not to be working is the sortedItems: function () {....
Can anyone see why the DOM is not updating?
The most probable is that sort() method doesn't recognize Date object precedence. Use js timestamp instead:
if (_this.sortDirection === 'newFirst') {
news.sort(function (a, b) {
var dateA = new Date(a.PostDate);
var dateB = new Date(b.PostDate);
return dateB.valueOf() - dateA.valueOf();
});
} else {
news.sort(function (a, b) {
var dateA = new Date(a.PostDate);
var dateB = new Date(b.PostDate);
return dateA.valueOf() - dateB.valueOf();
});
}
Got there eventually - thanks for your help
sortedItems: function () {
var _this = this;
var news = _this.allItems;
if (_this.sortDirection === 'newFirst') {
news.sort(function (a, b) {
var dateA = new Date(a.PostDate);
var dateB = new Date(b.PostDate);
return dateB.valueOf() - dateA.valueOf();
});
} else {
news.sort(function (a, b) {
var dateA = new Date(a.PostDate);
var dateB = new Date(b.PostDate);
return dateA.valueOf() - dateB.valueOf();
})
}
return news.filter(x => {
return _this.selectedType === "All" || x.Tag ===
_this.selectedType;
});
}

Configuring jqgrid search to search one of many

I'm having trouble either understanding or implementing search/filter functionality in jqgrid.
The data set is returned to the client with each item having a list of designers:
"IAConsultWorkflowRequestsList": [
{
"AppID": "ISP",
"SubmittedDate": "12/13/2018",
"IAAssigned": "<a style='color:blue !important;' href='mailto:Joseph#somewhere.com'><u>Joseph Kraft</u></a>",
"IAAssignedName": null,
"Status": "In Discovery",
"SLA": 0,
"DaysPassed": 157,
"IsUserFM": false,
"IsUserSecureEnv": false,
"DesignParticipants": [
{
"Name": "John Kraft",
"EmailAddress": "",
"ID": "A2049"
},
{
"Name": "Zack Adamas",
"EmailAddress": "Zachary.Adamas#somewhere.com",
"ID": "U6696"
},
{
"Name": "David Kosov",
"EmailAddress": "David.Kosov#somewhere.com",
"ID": "U6644"
}
]
}
So in the 'Designers' column, I am concatenating the results to be comma separated, e.g.
John Kraft,
Zack Adamas,
David Kosov
And, if the item has an email address, the individual name is formatted as an email link:
<td role="gridcell" style="text-align:center;" title="John Kraft,Zack Burns,David Cosand" aria-describedby="workFlowIAGrid_DesignParticipants">
John Kraft,<br>
<a style="color:blue !important;" ref="mailto:Zachary#somewhere.com"><u>Zack </u></a>,<br>
<a style="color:blue !important;" href="mailto:David#somewhere.com"><u>David </u></a></td>
I have a select element with entries John, Zack, and David, but when I select one of the options, I do not get expected results. If I select David, I would like to be shown any rows that contain David as one of potentially several names in the Designer column.
However, I am getting erratic behavior. Some of the sopt options will cause something to happen, but not what is expected. None of the contains/not contained or in/not in options seem to do what I need. What am I doing wrong?
Per Tony's comment, here is the grid init code:
$gridEl.jqGrid({
xhrFields: {
cors: false
},
url: "/IAConsult/GetWorkFlowIARequests",
postData: {
showAll: showAllVal,
role: role,
IsIAArchitect: userIsIA
},
datatype: "json",
crossDomain: true,
loadonce: true,
mtype: 'GET',
sortable: true,
viewrecords: true,
pager: '#workFlowIAGridPager',
multiselect: true,
rowNum: 50,
autowidth: true,
colModel: [
{ label: 'Design Participants', name: 'DesignParticipants', align: "center", formatter:commaSeparatedList },
//same for other columns...
],
beforeSelectRow: function (rowid, e) {
var $myGrid = $(this),
i = $.jgrid.getCellIndex($(e.target).closest('td')[0]),
cm = $myGrid.jqGrid('getGridParam', 'colModel');
return (cm[i].name === 'cb');
},
jsonReader: {
repeatitems: true,
root: "IAConsultWorkflowRequestsList"
},
beforeSubmitCell: function (rowid, name, value, iRow, iCol) {
return {
gridData: gridData
};
},
serializeCellData: function (postdata) {
return JSON.stringify(postdata);
},
gridComplete: function () {
rowCount = $gridEl.getGridParam('records');
gridViewRowCount = rowCount;
var rowIDs = $gridEl.getDataIDs();
var inCompleteFlag = false;
//Filter code to apply filter in headers in MyWork grid
var datatoFilter = $gridEl.jqGrid('getGridParam', 'lastSelectedData').length == 0
? $gridEl.jqGrid("getGridParam", "data")
: $gridEl.jqGrid('getGridParam', 'lastSelectedData');
var $grid = $gridEl, postfilt = "";
var getUniqueNames = function (columnName) {
var uniqueTexts = [],
mydata = datatoFilter,
texts = $.map(mydata, function(item) {
return item[columnName];
}),
textsLength = texts.length,
text = "",
textsMap = {},
i;
if (texts[0] && texts[0].Name)
texts = $.map(texts,
function(item) {
return item.Name;
});
for (i = 0; i < textsLength; i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
if (columnName == 'ConsultID') {
return (uniqueTexts.sort(function (a, b) { return a - b; }));
} else return uniqueTexts.sort();
}, buildSearchSelect = function (uniqueNames) {
var values = {};
values[''] = 'All';
$.each(uniqueNames,
function () {
values[this] = this;
});
return values;
}, setSearchSelect = function (columnName) {
var changedColumns = [];
this.jqGrid("setColProp",
columnName,
{
stype: "select",
searchoptions: {
value: buildSearchSelect(getUniqueNames.call(this, columnName)),
sopt: getSortOptionsByColName(columnName),
dataEvents: [
{
type: "change",
fn: function (e) {
setTimeout(function () {
//get values of dropdowns
var DesignParticipant = $('#gs_workFlowIAGrid_DesignParticipants').val();
//same for other columns...
var columnNamesArr = columns.split(',');
changedColumns.push(columnName);
for (i = 0; i < columnNamesArr.length; i++) {
if (true) {
var htmlForSelect = '<option value="">All</option>';
var un = getUniqueNames(columnNamesArr[i]);
var $select = $("select[id='gs_workFlowIAGrid_" + columnNamesArr[i] + "']");
for (j = 0; j < un.length; j++) {
var val = un[j];
htmlForSelect += '<option value="' + val + '">' + val + '</option>';
}
$select.find('option').remove().end().append(htmlForSelect);
}
}
$('#gs_workFlowIAGrid_DesignParticipants').val(DesignParticipant);
//same for other columns...
},
500);
//setting the values :
}
}
]
}
});
};
function getSortOptionsByColName(colName) {
console.log(colName);
if (colName === 'DesignParticipants')
return ['in'];
else
return ['eq'];
}
setSearchSelect.call($grid, "DesignParticipants");
//same for other columns...
$grid.jqGrid("filterToolbar",
{ stringResult: true, searchOnEnter: true });
var localFilter = $gridEl.jqGrid('getGridParam', 'postData').filters;
if (localFilter !== "" && localFilter != undefined) {
globalFilter = localFilter;
}
$gridEl.jqGrid("setGridParam",
{
postData: {
"filters": globalFilter,
showAll: showAllVal,
role: role,
IsIAArchitect: userIsIA
},
search: true,
forceClientSorting: true
})
.trigger("reloadGrid");
//Ending Filter code
var columnNamesArr = columns.split(',');
for (i = 0; i < columnNamesArr.length; i++) {
if (true) {
var htmlForSelect = '<option value="">All</option>';
var un = getUniqueNames(columnNamesArr[i]);
var $select = $("select[id='gs_workFlowIAGrid_" + columnNamesArr[i] + "']");
for (j = 0; j < un.length; j++) {
val = un[j];
htmlForSelect += '<option value="' + val + '">' + val + '</option>';
}
$select.find('option').remove().end().append(htmlForSelect);
}
}
},
// all grid parameters and additionally the following
loadComplete: function () {
$gridEl.jqGrid('setGridWidth', $(window).width(), true);
$gridEl.setGridWidth(window.innerWidth - 20);
},
height: '100%'
});
Here is the formatter I am using on the column:
function commaSeparatedList(cellValue, options, rowdata, action) {
let dps = [];
_.forEach(cellValue, function (item) {
let formatted = '';
if (item.EmailAddress)
formatted += '<a style="color:blue !important;" href="mailto:' +
item.EmailAddress +
'"><u>' +
item.Name +
'</u></a>';
else formatted = item.Name;
dps.push(formatted + ',<br/>');
});
let toString = dps.join('');
return toString.substring(0,toString.length-6);
}
And then the only other pertinent thing is that I used a function to return 'in' (or some other key - these are the options I said weren't apparently working in the initial post) if the column is named 'Design Participants', else equal for any other column:
setSearchSelect = function (columnName) {
var changedColumns = [];
this.jqGrid("setColProp",
columnName,
{
stype: "select",
searchoptions: {
value: buildSearchSelect(getUniqueNames.call(this, columnName)),
sopt: getSortOptionsByColName(columnName),
dataEvents: [
{...
function getSortOptionsByColName(colName) {
console.log(colName);
if (colName === 'DesignParticipants')
return ['in'];
else
return ['eq'];
}
The issue was that the underlying data (the DesignParticipants in the returned JSON above) did not match the selected string, since the data itself was an array. I believed the filtering was based on the displayed text in the grid table, but, it was based on the underlying data. So, I created a new property of the returned JSON that was a string, and the filtering worked as expected.

nightwatch assert ALL elements, not ANY

I'm trying to test that, when the Submit button is clicked on an empty form, all the "please fill in this field" labels are displayed.
I'm doing so with this:
page.click('#btn_submit');
page.expect.element('#validation_label_required').to.be.visible;
where #validation_label_required is represented by the CSS selector:
input[required] ~ p.error-message-required
However, this test passes if ANY of the validation labels are visible. The test should only pass if they ALL are.
How can I achieve this?
You will need to create a custom assertion for that where you locate all elements by selenium commands and then loop to verify condition. It should look something like this
var util = require('util');
exports.assertion = function (elementSelector, expectedValue, msg) {
this.message = msg || util.format('Testing if elements located by "%s" are visible', elementSelector);
this.expected = expectedValue;
this.pass = function (value) {
return value === this.expected;
};
this.value = function (result) {
return result;
};
this.command = function (callback) {
var that = this.api;
this.api.elements('css selector',elementSelector, function (elements) {
elements.value.forEach(function(element){
that.elementIdDisplayed(element.ELEMENT,function(result){
if(!result.value){
callback(false);
}
});
});
callback(true);
});
return this;
};
};
I've just ended up with another custom assertion that check how many elements are visible by given css selector.
/**
* Check how many elements are visible by given css selector.
*
*/
var util = require('util');
exports.assertion = function(elementSelector, expectedCount, msg) {
this.message = msg || util.format('Asserting %s elements located by css selector "%s" are visible', expectedCount, elementSelector);
this.expected = expectedCount;
this.count = 0;
this.pass = function(value) {
return value === this.expected;
};
this.value = function(result) {
return this.count;
};
this.command = function(callback) {
var me = this, elcount = 0;
this.count = 0;
this.api.elements('css selector', elementSelector, function(elements) {
if(elements.value && elements.value.length > 0){
elcount = elements.value.length;
}else{
return callback(false);
}
elements.value.forEach(function(element) {
me.api.elementIdDisplayed(element.ELEMENT, function(result) {
if (result.value) {
me.count++;
}
elcount--;
if (elcount === 0) {
callback(me.count);
}
});
});
});
};
};

SlickGrid filter not working

I am fairly new to SlickGrid. I am trying to make SlickGrid filter work but no luck. I am following the example (http://mleibman.github.io/SlickGrid/examples/example4-model.html).
Below is my source code.
$(document).ready(function() {
var tName;
$('#submit').click(function(e) {
tName = $('#source option:selected').text();// name1
tName = tName.trim();
$.ajax({
url : 'someUrl',
type : 'GET',
cache : false,
success : function(d) {
var grid;
var searchString = "";
var data = [];
var columns = new Array();
var cols = d[0].columns;
var pkColNames = d[0].pkColNames;
for (var j=0; j< cols.length; j++) {
var key = {id: cols[j].colName, name: cols[j].colName, field: cols[j].colName, width: 200, sortable:true, editor: Slick.Editors.LongText};
columns[j] = key;
}
var options = {
editable: true,
enableAddRow: false,
enableCellNavigation: true,
asyncEditorLoading: false,
enableColumnReorder:true,
multiColumnSort: false,
autoEdit: false,
autoHeight: false
};
function myFilter(item, args) {
return true;// Let us return true all time ?
}
for (var i = 0; i < d.length; i++) {
var tempData = (data[i] = {});
var title = null;
var val = null;
for (var q = 0; q < d[i].columns.length; q++) {
title = d[i].columns[q].colName;
val = d[i].columns[q].colValue;
tempData[title] = val;
}
}
var dataView = new Slick.Data.DataView({ inlineFilters: true });
grid = new Slick.Grid("#myGrid", dataView, columns, options);
dataView.setPagingOptions({
pageSize: 25
});
var pager = new Slick.Controls.Pager(dataView, grid, $("#myPager"));
var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);
grid.setSelectionModel(new Slick.CellSelectionModel());
grid.onAddNewRow.subscribe(function(e, args) {
// Adding a new record is not yet decided.
});
grid.onCellChange.subscribe(function (e) {
var editedCellNo = arguments[1].cell;
var editedColName = grid.getColumns()[editedCellNo].field;
var newUpdatedValue= arguments[1].item[grid.getColumns()[editedCellNo].field];
var editedColType = "";
for (var cnt = 0; cnt < cols.length; cnt++) {
if (editedColName == cols[cnt].colName) {
editedColType = cols[cnt].colType;
break;
}
}
var pkKeyValue="";
for (var v=0; v <pkColNames.length;v++) {
for (var p=0; p<grid.getColumns().length; p++) {
if (pkColNames[v] == grid.getColumns()[p].field) {
var value = arguments[1].item[grid.getColumns()[p].field];
pkKeyValue += "{"+pkColNames[v] + '~' +getColDbType(grid.getColumns()[p].field) + ":"+value+"},";
break;
}
}
}
function getColDbType(colName) {
for (var c = 0; c < cols.length; c++) {
if (colName == cols[c].colName) {
return cols[c].colType;
}
}
}
pkKeyValue = pkKeyValue.substring(0, pkKeyValue.length-1);
$.ajax({
url: 'anotherUrl',
type:'GET',
dataType:'text',
success: function(f) {
bootbox.alert("Data updated successfully");
},
error: function() {
bootbox.alert("Error - updating data. Please ensure you are adding the data in right format.");
grid.invalidateAllRows();
grid.render();
}
});
});
grid.onClick.subscribe(function (e) {
//do-nothing
});
dataView.onRowsChanged.subscribe(function(e, args) {
grid.updateRowCount();
grid.invalidateRows(args.rows);
grid.render();
});
grid.onSort.subscribe(function(e, args) {
// args.multiColumnSort indicates whether or not this is a multi-column sort.
// If it is, args.sortCols will have an array of {sortCol:..., sortAsc:...} objects.
// If not, the sort column and direction will be in args.sortCol & args.sortAsc.
// We'll use a simple comparer function here.
var comparer = function(a, b) {
return a[args.sortCol.field] > b[args.sortCol.field];
}
// Delegate the sorting to DataView.
// This will fire the change events and update the grid.
dataView.sort(comparer, args.sortAsc);
});
// wire up the search textbox to apply the filter to the model
$("#txtSearch").keyup(function (e) {
console.log('Called...txtSearch');
Slick.GlobalEditorLock.cancelCurrentEdit();
// clear on Esc
if (e.which == 27) {
this.value = "";
}
searchString = this.value;
updateFilter();
});
function updateFilter() {
console.log("updateFilter");
dataView.setFilterArgs({
searchString: searchString
});
dataView.refresh();
}
dataView.beginUpdate();
dataView.setItems(data, pkColNames);
dataView.setFilterArgs({
searchString: searchString
});
dataView.setFilter(myFilter);
dataView.endUpdate();
},
error : function() {
bootbox.alert("Invalid user");
}
});
});
});
Your function myFilter() is always returning true so of course it will never work. The example that you looked at, was to filter something specific. I would recommend that you look at the following example to have a generic filter. From the example, simply type the text you are looking on a chosen column and look at the result... see example below (from SlickGrid examples).Using fixed header row for quick filters
In case you want a more in depth conditional filters ( > 10, <> 10, etc...), please take a look at my previous answer on how to make this kind of filtering possible, see my previous answer below:SlickGrid column type
Hope that helps you out

Adding new row to SlickGrid

I have a slickgrid using the dataview. From what I can tell, the grid's add new row event isn't called until after the first new row field's editor is complete. The field I was editing is a custom editor that uses a input box with autocomplete and save the selected item "value" to the grid source data. The problem is the new "item" source isn't created until the grid add new row event is fired. I know there is a way around this and just want to know what is the best way to solve for this.
Thanks.
//Add new row event
grid.onAddNewRow.subscribe(function (e, args) {
var item = args.item;
addnewid = addnewid - 1;
item.inventorytransferdetailid = addnewid;
$.extend(item, args.item);
dataView.addItem(item);
});
// Custom editor
function Suggest2(args) {
var $input;
var defaultValue;
var scope = this;
this.init = function () {
$input = $("<INPUT type=text class='editor-text' />")
$input.width = args.column.width;
$input.appendTo(args.container);
$input.focus();
$input.bind("keydown.nav", function (e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
else if ($input.val().length > 0) {
$.ajax({
type: "GET",
url: "http://localhost:11111/GetProducts/" + $input.val(),
dataType: "json",
data: "{}",
contentType: "application/json; charset=utf-8",
success: function (data) {
$input.autocomplete({
source: data,
select: function (event, ui) {
var v = ui.item.value;
var l = ui.item.label;
//Set "display" field with label
args.item[args.column.field] = l;
this.value = l;
//Set "hidden" id field with value
args.item["productid"] = v;
return false;
}
});
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
}
})
};
this.destroy = function () {
$input.remove();
};
this.focus = function () {
$input.focus();
};
this.getValue = function () {
return $input.val();
};
this.setValue = function (val) {
$input.val(val);
};
this.loadValue = function (item) {
defaultValue = item[args.column.field] || "";
$input.val(defaultValue);
$input[0].defaultValue = defaultValue;
$input.select();
};
this.serializeValue = function () {
return $input.val();
};
this.applyValue = function (item, state) {
//item[args.column.field] = state;
};
this.isValueChanged = function () {
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
};
this.validate = function () {
if (args.column.validator) {
var validationResults = args.column.validator($input.val());
if (!validationResults.valid) {
return validationResults;
}
}
return {
valid: true,
msg: null
};
};
this.init();
}
You can try below code.
function add_new_row(){
item = {
"id": (Math.round(Math.random()*-10000))
};
data_view.insertItem(0, item);
}
Then, bind with button.
<button onclick="add_new_row()">Add Row</button>

Resources