Mat-table reset mat-sort to initial state - angular-material

I have a mat-table in which I have several sort-able column. I can set the initial sort of the table with the matSortActive and matSortDirection properties on the mat-table. Using this, the arrow indicating the sorting direction in the headers is displayed correctly.
Now when I am trying to reset the sorting to the initial state by using a button the sorting is correctly reset. However, the arrow in the header is not updated. So the arrow is still displayed in the header of the previous sorted column.
How can I get the arrow to be displayed in the initial state again?
My table and reset button in HTML:
<button mat-button mat-raised-button (click)="removeFilters()" class="reset-button">Verwijder filters</button>
<mat-table #table [dataSource]="dataSource" matSort (matSortChange)="sortData($event)" matSortActive="comp_name_sort" matSortDirection="asc">
<ng-container matColumnDef="assetName">
<mat-header-cell *matHeaderCellDef mat-sort-header="comp_name_sort">Systeem</mat-header-cell>
<mat-cell *matCellDef="let asset"> {{asset.comp_name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="softwareName">
<mat-header-cell *matHeaderCellDef mat-sort-header="soft_name_sort">Software</mat-header-cell>
<mat-cell *matCellDef="let asset"> {{asset.soft_name}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
My ts file:
export class AssetsComponent implements OnInit {
#ViewChild(MatSort) sort: MatSort;
assets: Asset[];
displayedColumns = ['assetName', 'softwareName',];
dataSource = new MatTableDataSource<Asset>(this.assets);
constructor( private assetsService: AssetsService) { }
ngOnInit() {
this.getAssets();
}
getAssets(): void {
this.assetsService.getAssets().subscribe(
assets => {
this.assets = assets;
this.dataSource = new MatTableDataSource<Asset>(this.assets);
}
);
}
sortData(event): void {
this.assetsQueryService.setSorts(event);
this.getAssets();
}
removeFilters() {
this.sort.active = 'comp_name_sort';
this.sort.direction = 'asc';
this.sort.sortChange.emit({active: 'comp_name_sort', direction: 'asc'});
this.assetsQueryService.removeFilters();
this.getAssets();
}
}
The sorting column and direction are passed to the assetsService because sorting is done in the backend (because of server-side pagination, not shown here). This is all working well, also with the reset button. The only problem is the displayed arrow.
So in summary, how do I reset the sorting arrow that is displayed in the table to it's initial state programmatically?
Any help would be appreciated.

For anyone else looking for an answer for this particular problem. As ericbea pointed out in the comments, Angular is aware of this problem and an issue is still open on github about this: https://github.com/angular/components/issues/10242.
The only workaround that I found that worked for me is also listed there. It's something like this:
this.sort.sort({ id: null, start: 'desc', disableClear: false });
this.sort.sort({ id: 'comp_name_sort', start: 'asc', disableClear: false });
(this.sort.sortables.get('comp_name_sort') as MatSortHeader)._setAnimationTransitionState({ toState: 'active' });
The first line is used to clear the sort in case the column you want the sort to is currently the active column.

I don't know if you still need help with this, but I encountered the same issue and here's my solution. After you reset the active and direction for your sort, add the following line:
this.sort._stateChanges.next();
This should remove the sort arrow from your UI. Hopefully this helps!

Maybe you should try ChangeDetectorRef, it could just be that the view is not being refreshed properly after the change.
This is usually useful when the view needs a refresh after a change that doesn't require user interaction with the view.
Just inject the change detector in your component like this:
constructor( private changeDetector: ChangeDetectorRef ) { }
and then use it just after reset the sort state programatically to force the view to detect changes like this:
this.changeDetector.detectChanges();
Hope it helps ;)

I know this question is old but in case anyone else comes looking...
To set the arrow in the sort header, this worked for me:
import { MatSort } from '#angular/material/sort'
Then, in the class:
#ViewChild(MatSort) myMatSort:MatSort
Finally, you can do this:
myMatSort.sort({
id: 'column-name', // The column name specified for matColumnDef attribute
start: 'asc', // Can be 'asc', 'desc' or null,
disableClear: false
})
See the sort method and MatSortable interface here.

Using Angular 6+,
if you want sort-reset DESCENDING:
defaultSortStart: 'desc', defaultSortDirection: 'asc'
if you want sort-reset ASCENDING:
defaultSortStart: 'asc', defaultSortDirection: 'desc'
// Reset sort: FIELD_NAME/DESC.
let defaultSortStart: ('asc' | 'desc') = 'desc';
let defaultSortDirection: ('asc' | 'desc') = 'asc';
let defaultSortField = this.matListColumnName.FIELD_NAME;
this.sort.direction = defaultSortDirection;
this.sort.sort({
id: defaultSortField,
start: defaultSortStart,
disableClear: true
});
// Reset sort: FIELD_NAME/ASC.
let defaultSortStart: ('asc' | 'desc') = 'asc';
let defaultSortDirection: ('asc' | 'desc') = 'desc';
let defaultSortField = this.matListColumnName.FIELD_NAME;
this.sort.direction = defaultSortDirection;
this.sort.sort({
id: defaultSortField,
start: defaultSortStart,
disableClear: true
});

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']

easyui edatagrid Set Default Value for Numberbox

Can anyone help me with a problem I am having. I'm using JEasyUI eDataGrid, and when inserting a new record I would like the numberbox fields to automatically have a 0 in them.
Table portion
<th field="Defect" width="50">Defect</th>
Script
$(function(){
$('#dg').edatagrid({
url: ...
emptyMsg: 'No Record(s) Found',
columns:[[
{field:'Defect',title:'Defect',width:100,
formatter:function(value,row){
return row.Defect|| value;
},
editor:{
type:'numberbox',
options:{
required:true,
min:0,
*value: 0,*
}
Looking through the documentation, adding a value property should set a default value but it does not.
Figured out the answer. What I needed to do was add the following to my script.
onBeginEdit: function(index,row){
var ed = $(this).datagrid('getEditor',{index:index,field:'defect'});
$(ed.target).numberbox('setValue', 0)
},

array observable with content observable and jqAutocomplete

I'm using Knockout 3 with the plugin jqAutocomplete by Ryan Niemeyer. I have a problem with this model:
var ViewModel = function() {
var self = this;
self.myOptionsObs = ko.observableArray([
{ id: ko.observable(1), name: ko.observable("item 1 o"), description: ko.observable("item label 1 o") },
{ id: ko.observable(2), name: ko.observable("item 2 o"), description: ko.observable("item label 2 o") },
{ id: ko.observable(3), name: ko.observable("item 3 o"), description: ko.observable("item label 3 o") }
]);
self.myValueObs = ko.observable();
};
ko.applyBindings(new ViewModel());
<input data-bind="jqAuto: { source: myOptionsObs, value: myValueObs, inputProp: 'name', template: 'itemTmpl' }" />
As you can see, there is an observable array and each element is also an observable.
The autocomplete don't work well. As you can see in this Fiddle, the left column has an observable array but its elements aren't observable. If you click in the left box and write something, a list of options appear.
But in the right column, you have the same, but the element's are all observable. If you click in the right box and write something, when the list appear, if you move the cursor up and down, you could see that the row 'name' gets deleted and filled with zeros.
What I have to change in my data-bind attribute?
This question is related with this question.
I have to say that this solution works ok for me. But the updated plugin don't.
Thanks !!
The jqAutoComplete plugin isn't setup to work with observable properties (although it could be enhanced to do so without much work).
For now, I think that your best bet is to create a computed that will always return a plain and up-to-date version of your options.
self.myOptionsObs.plain = ko.computed(function() {
return ko.toJS(self.myOptionsObs);
});
Sample: http://jsfiddle.net/rniemeyer/45cepL9b/
I'll try to take a look at some point about supporting observable properties. Shouldn't take many changes.

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;

Wix populate listbox

I am trying to fill in a ListBox with CustomAction and it's not going well.
I try to figure out the session.Database.Tables but have no idea how to start.
I've created a listbox like this
<Control Id="ListBox1" Type="ListBox" Sorted="no" Indirect="no" Property="LISTBOXVALUESONE" X="10" Y="50" Width="150" Height="180">
<ListBox Property="LISTBOXVALUESONE">
<ListItem Text="ARGHH!" Value="1"/>
</ListBox>
</Control>
But I cant see the property in my verbrose log or anything about an table so I guess I have to create an table in customAction and populate it?
I see my ARGHH! in the list so it should exsist but how do I access the values? And add new ones?
Found more examples and stuff in C++ but i would like to make the CustomAction in C#
EDIT
Database db = session.Database;
string sqlInsertTemp = db.Tables["ListBox"].SqlInsertString + " TEMPORARY";
View view = db.OpenView(sqlInsertTemp );
view.Execute( new Record( new object[] { "LISTBOXVALUESONE", 2, "2", "One" } ));
view.Close();
Thanks to Christopher I got it to work with adding an value.
db.Tables["ListBox"] should remain the same and name the type not the id as i taught
And on this line view.Execute( new Record( new object[] { "LISTBOXVALUESONE", 2, "2", "One" } ));
you put your Listbox Property and then the placement of the value "one" we insert
The two "2"s is what I figure the placement we want it on and I already have an test value on 1
my "ARGHH!" so I put the new on 2 and dont know the details but...
I got an Table Update error and, one dublicate value error if i put 2,1 or 1,2 in the customaction!
I wrote a blog article about 5 years ago that might help you:
How DTF is going to help me become a better .NET Developer
You want to make sure your built MSI has a ListBox table otherwise the SQL won't work when it tries to generate the temp rows dynamically at runtime. If the ListBox element doesn't do this for you, the EnsureTable element will.
The actual C# looks something like:
Database db = session.Database;
string sqlInsertTemp = db.Tables["ListBox"].SqlInsertString + " TEMPORARY";
View view = db.OpenView(sqlInsertTemp );
view.Execute( new Record( new object[] { "TESTPROP", 1, "1", "One" } ));
view.Close();
Note this is an old code example and doesn't properly take advantage of using statements and IDisposable.
Add one record to list box:
private void AddRecordToListBox(string listBoxPropertyName, int index, string text, string value)
{
View view = session.Database.OpenView("SELECT * FROM ListBox");
view.Execute();
Record record = session.Database.CreateRecord(4);
record.SetString(1, listBoxPropertyName);
record.SetInteger(2, index);
record.SetString(3, value);
record.SetString(4, text);
view.Modify(ViewModifyMode.InsertTemporary, record);
view.Close();
}
Fill ListBox:
private void FillListBox()
{
var dict = SomeDict();
int index = 1;
foreach (var element in dict)
{
AddRecordToListBox(ListBoxName, index, element.Key, element.Value);
index++;
}
}
Clear ListBox
private void ClearListBox(string listBoxPropertyName)
{
var command = String.Format("DELETE FROM ListBox WHERE ListBox.Property='{0}'", listBoxPropertyName);
View view = session.Database.OpenView(command);
view.Execute();
view.Close();
}

Resources