Calculating columns when upgrading to ui-grid 3.0 from ng-grid - angular-ui-grid

I have a plunker to demonstrate my issues.
1 Issue: Totals column is blank
I need to calculate the columns (Total) so I have a $scope method as follows:
$scope.getTotal = function(a, b, c, d, e) {
return $filter('number')(Number(a) + Number(b) + Number(c) + Number(d) + Number(e), 2);
};
and the cellTemplate to make that call:
<div class="padd black">
{{getExternalScopes().getTotal(row.entity.M,row.entity.T,row.entity.W,row.entity.H,row.entity.F)}}
</div>
and in columnDefs, I use:
{
field: 'total',
displayName: 'Total',
enableColumnMenu: false,
type: 'number',
cellFilter: 'number:1',
cellClass: 'text-right',
headerCellClass: 'text-center',
cellTemplate: 'total.tmpl.html',
width: '10%'
}
[2] Issue: ng-class not working in template, pending.icons.html
We use icons to indicate status of a record and in the template, I am using a conditional for ng-class which should control the color of the icon but it is being ignored and all icons are colored black:
ng-class="{'cBlue': grid.getCellValue('vote_pending'), 'cGray': !grid.getCellValue('need_vote')}"

Uhh, this answer may only be a partial.
Since v3 the external scopes are (probably) gone and have been replaced by grid.appScope.function_xxx(). Read more here
So you have to leave out the external scopes part in your markup:
<div ui-grid="gridOptions" ui-grid-edit ui-grid-cellNav class="grid"></div>
The function for calculation in your scope should be:
$scope.getTotal=function(a, b, c, d, e) {
return a+b+c+d+e;
};
(I left the filtering and number stuff out)
And your cell template would now be:
<div class="padd black">
{{grid.appScope.getTotal(row.entity.M,row.entity.T,row.entity.W,row.entity.H,row.entity.F)}}
</div>
This seems to work here: Plunker
Since I'm on my way home now, I'll check for your 2nd Issue later.
Hope this helps so far.
Update:
2nd Issue:
Use this in pending.icons.html :
ng-class="{'cBlue': row.entity.vote_pending, 'cGray': !row.entity.vote_pending}"
Works for me (allthough my Plunker is very, veeery slow at the moment)
Look here

Related

Need assistance reading the object returned by getRowId of MaterialReactTable

I am using MaterialReactTable in my application and following the Row Selection Option as outlined at this link: https://www.material-react-table.com/docs/guides/row-selection
The table is working fine and I am able to select the row I want and it returns the correct id but returns it in the format: rowSelection = {63d19bebc764a5587a48683a: true}. I am not familiar with this format.
I have tried everything I know but am unable to parse out the id from the object.
Please provide suggestion to parse out the id or suggest changes to make this solution work.
I have tried the other methods of row selection suggested on the page (useRef and '#tanstack/react-table') and could not get either to work so would like to stick to this method as I feel it is close.
Below is the code and options I am using with the MaterialReactTable
return (
<MaterialReactTable
columns={columns}
data={data}
enableRowSelection
onRowSelectionChange={setRowSelection}
enableMultiRowSelection={false}
//getRowId={(row) => row?._id }
getRowId={(originalRow) => originalRow._id}
initialState={{ showColumnFilters: true,
columnVisibility:
{ _id: false } }} //hide columns listed to start }}
manualFiltering
manualPagination
manualSorting
muiToolbarAlertBannerProps={
isError
? {
color: 'error',
children: 'Error loading data',
}
: undefined
}
muiTableBodyRowProps={({ row }) => ({
//add onClick to row to select upon clicking anywhere in the row
onClick: row.getToggleSelectedHandler(),
sx: { cursor: 'pointer' },
})}
onColumnFiltersChange={setColumnFilters}
onGlobalFilterChange={setGlobalFilter}
onPaginationChange={setPagination}
onSortingChange={setSorting}
rowCount={rowCount}
state={{
columnFilters,
globalFilter,
isLoading,
pagination,
showAlertBanner: isError,
showProgressBars: isRefetching,
sorting,
rowSelection
}}
/>
);
Given the format of the response, rowSelection = {63d19bebc764a5587a48683a: true}, I had originally assumed a key: value pair with the id being the key. My initial attempts to parse out the id as the key had failed. After trying a number of different options, I was able to use the Object.keys() function as follows:
console.log(Object.keys(rowSelection)); //used to view the key(s) returned
setCurrentRoom(Object.keys(rowSelection));
This code converted the id to a string in an array as follows: currentRoom = ['63d19bd9c764a5587a486836']

Free Text Entry in Angular Material mdAutoComplete

I want my angular material autocomplete to be a list of suggestions but not requirements. However I'm not sure how to implement as their is no clear example from the Angular Material docs.
In the example below my model is $ctrl.item.category
Clearly the example below is wrong, as my model is linked to md-selected-item, but this only works if I select an item. I want the user to be able to free enter the text if the item is not in the list. Basically how autocomplete already works in most browsers.
I see plenty of questions on how to disable this, but they are not trying to disable so much as clean up the left over text when an item is not selected. In these cases when an item is not selected then the model value is null, but text is left in the input.
I want the text left int he input to be the model value if the person does not select (or a match is not made).
md-autocomplete(
md-floating-label="Category Name"
flex="50"
md-input-name="category"
md-selected-item="$ctrl.item.category"
md-search-text="catSearch"
md-items="category in $ctrl.categories"
md-item-text="category"
md-min-length="0"
md-select-on-match=""
md-match-case-insensitive=""
required=""
)
md-item-template
span(md-highlight-text="catSearch" md-highlight-flags="^i") {{category}}
My options ($ctrl.categories) is an array of strings ['Food','Liqour'] and I wan the user to be able to use one of those or free enter Tables as their choice.
In this case you should link md-search-text to your model.
If you want to implement fuzzy search you have to write the filter method yourself. Look at this example:
template:
<md-autocomplete
md-items="item in $ctrl.itemsFilter()"
md-item-text="item.label"
md-search-text="$ctrl.query"
md-selected-item="$ctrl.selected"
>
<md-item-template>
<span md-highlight-text="$ctrl.query">{{item.label}}</span>
</md-item-template>
<md-not-found>
No item matching "{{$ctrl.query}}" were found.
</md-not-found>
<div ng-messages="$ctrl.myValidator($ctrl.query)">
<div ng-message="short">Min 2 characters</div>
<div ng-message="required">Required value</div>
</div>
</md-autocomplete>
controller:
var items = [ ... ];
ctrl.itemsFilter = function itemsFilter() {
return ctrl.query ? filterMyItems(ctrl.query) : items;
};
ctrl.myValidator = function (value) {
return {
short: value && value.length < 2,
required : value && value.length < 1,
};
};
then you just need to add filterMyItems method to filter your items
To improve the answer of #masitko, I have implemented the filter in a way, that it adds the query to the filtered list. So it becomes selectable and a valid option. So it's possible to make the autocomplete a suggestion box.
I'm using ES6 in my projects. But it should be easily adaptable to ES5 code.
myFilter() {
if (!this.query) return this.items;
const
query = this.query.toLowerCase(),
// filter items where the query is a substing
filtered = this.items.filter(item => {
if (!item) return false;
return item.toLowerCase().includes(query);
});
// add search query to filtered list, to make it selectable
// (only if no exact match).
if (filtered.length !== 1 || filtered[0].toLowerCase() !== query) {
filtered.push(this.query);
}
return filtered;
}

How do you set the tablesorter default filter type

I have a tablesorter table with titles in the cells. I'd like to be able to search on multiple, non-contiguous words in the title. The fuzzy match (~) does the job. How do I get this to be the default matcher? I don't want my users to have learn/remember it.
I tried a custom filter like this
....
widgetOptions: {
filter_external: '.search', // input box that user input goes into
filter_columnFilters: false,
filter_functions : {
1: function (e, n, f, i, $r) {
return this.filter.types.fuzzy( e, '~' + n, f, i, $r);
}
}
}
.....
but that didn't work. Ideas?
I just added a new filter widget option filter_defaultFilter in the working branch of the GitHub repository
To use it, include the column class name or index and a filter mask with the filter selector (~ in your case) and a query tag ({query} or {q}).
$(function () {
$('table').tablesorter({
theme: 'blue',
widgets: ['zebra', 'filter'],
widgetOptions: {
filter_defaultFilter: {
// set default fuzzy match on first column
0 : '~{q}'
}
}
});
});
Here is a demo applying a default exact match to filter selects for issue #704.
The documentation is available now in the working branch. The main documentation won't be updated until this weekend.

AngularJS and jqueryUI apply new index of list elements

I'm currently finishing a feature with list reordering and I'm stuck with a probably very simple thing, but I'm really sorry that I can't figure out how to solve it .... ( possibly my brain just ignores this logic :) )
The purpose is simple :
I have a list of items with a "position" data (different from $index).
I drag and drop items to change their order.
When the drag stops, all items in the list should have a new position, that'll be updated with a $resource object.
For example, after dragging I have this:
$index elem.position
0 2
1 1
2 3
should automatically change position 2->1, 1->2 and 3->3.
The problem :
With angularUI I can have the current item index but not the others in the list. So I can't change the whole list index after stopping the drag. And it's frustrating because on view, I can catch easily $index but not in controller.
Code :
in controller.js
$scope.updateSortable = {
stop: function(e, ui) {
for (var i=0; i<$scope.list.length; i++) {
var elem = $scope.list[i];
// here's don't know how to update elem.position
//elem.position = ui.item.index; // bad one, I know :)
//elem.$update();
}
},
placeholder: "xp-hightlight",
axis: 'y'
};
in html page :
<div ng-repeat="el in list">
<div>
<span class="position" ng-bind="el.position"></span>
</div>
</div>
The json items look like that :
{ id: 47, description: "my text in the list", position: 1}
Would this work for you, or do you have to have the position variable set?
<div ng-repeat="el in list">
<div>
<span class="position">{{$index + 1}}</span>
</div>
</div>
I added this to your controller 'testCtrl'. You can update the position element within the callback of this watch:
var _list;
$scope.$watch(function() {
return JSON.stringify($scope.items)
},function(_l) {
if(typeof _l !== 'undefined') {
_list = JSON.parse(_l);
console.log(_list)
}
});
I just solved the issue, and thanks to koolunix I managed the update of position directly inside the controller with this plunkr :
http://plnkr.co/edit/kDkNLSjoHbnaumk2uaOF?p=preview
The main fact was just to manage the position with the loop in list items.
elem.position=i+1;

Is it possible to combine different type of Toolbar definition in Kendo Grid?

I have some old code that defines a toolbar in the grid like this:
#(Html.Kendo().Grid<Object>().Name("SomeGrid")
.ToolBar(toolBar => toolBar.Custom()
.Text("<i class='icon-download'></i> Exportieren")
.HtmlAttributes(new { id = "export" })
.Url(Url.Action("Export", "ControllerName", new { page = 1, pageSize = "~", filter = "~", sort = "~", ElementId= ViewBag.CurrKompfGrp }))
)
...
I'd like to add more buttons into it.
The best way I found and use so far in other grids is with .Template function:
.ToolBar(toolbar =>
{
toolbar.Template("<a class='btn' id='panelAddAktionButton' onclick='aktionen.addItem();'><i class='icon-plus' rel='tooltip' title='add action'></i> </a> " +
"<a class='btn' id='panelEditAktionButton' onclick='aktionen.editItem();'><i class='icon-edit' rel='tooltip' title='Edit action'></i> </a> ");
})
However, the problem is that I cannot see how I can easily convert one approach into another.
When I try to add several items into the approach number 1, the Visual studio underlines it as an error.
And as the url is dynamic in the first approach, it is problematic to transform it into the second one.
I also tried to combine two - but got error again.
Any ideas are appreciated!
In case someone has the same problem. Kendo guys answered that the two approaches cannot be combined. If a toolbar template is added, it overrides all of the previous content. Nevertheless multiple custom commands could be defined, when the initial approach is used and an object is passed to the Toolbar Action Builder.
I had some more issues trying to use toolbar.Custom() with bootstrap buttons (an empty unnecessary element appeared near each button, but Kendo people said that this is not a bug). So I ended up doing this:
.ToolBar(toolbar =>
{
toolbar.Template("<a class='btn' id='panelDownloadItemButtonPLZ' onclick=lokaleSperrlisten.downloadSperrliste('grid41897')><i class='icon-download' rel='tooltip' title='Download'></i> </a> " +
"<a class='btn ' href='" + Url.Action("ExportSperrlisten", "Vorbereitung", new { page = 1, pageSize = "~", filter = "~", sort = "~", sperrlistenType = "PLZ" }) + "' id='export1'><i class='icon-inbox' rel='tooltip' title='Export'></i> </a>");
})
Thus, the best approach was to convert everything to Template() structure.
Hope, this helps someone else.

Resources