Select All checkboxes by default in nested mat table not working as expected - checkbox

I have a nested mat table with expandable rows . Only the inner table has checkbox and by default all the checkbox has to be checked in all the nested tables . Here is the working stackblitz
https://stackblitz.com/edit/angular-nested-mat-table-triplenested-iavs62?file=app%2Ftable-expandable-rows-example.ts
getProjectDetails(element: any) {
console.log(element.Id);
this.tableService.getInnerData(element.Id).subscribe((res) => {
if (res.length == 0) {
element['usersdataSource'] = new MatTableDataSource();
} else {
element['usersdataSource'] = new MatTableDataSource(res);
this.userSelectionMap.set(
element.Id,
new SelectionModel<any>(true, [element['usersdataSource']])
); // provided datasource of the current inner table for default sselection
}
});
}
I have provided the value of datasource for default selection while defining the selection model but it is not working as expected . I dont want to iterate over each table and do the selection as the data of inner table can be huge . What could be the best way to implement this ?

When you instantiate your SelectionModel, you need to pass element['usersdataSource'].data instead of [element['usersdataSource']].
getProjectDetails(element: any) {
console.log(element.Id);
this.tableService.getInnerData(element.Id).subscribe((res) => {
if (res.length == 0) {
element['usersdataSource'] = new MatTableDataSource();
} else {
element['usersdataSource'] = new MatTableDataSource(res);
this.userSelectionMap.set(
element.Id,
new SelectionModel<any>(true, element['usersdataSource'].data) // here
); // init userSelection of the current inner table
}
});
}

Related

material-table: How to make a summary row?

How can I make a summary row like this using a material table?
Please help me, thank you.
If by "Summary row" you're referring to table title, that's a prop "title" you just add to the <MaterialTable /> component.
However, I suspect you need the row with Total result, which I couldn't find in the examples, either.
Here's a custom function you could use to calculate a total by your own, add it to your data set and achieve similar result:
const addTotal = (data, byColumn) => {
let keys = Object.keys(data[0]);
let total = data.reduce((acc, el) => {
return acc += +(el[byColumn]);
}, 0);
let totalRow = {};
let emptyRow = {};
for (let key of keys) {
if (key === keys[0]) {
totalRow[key] = 'Total';
} else if (key === byColumn) {
totalRow[key] = total;
} else {
totalRow[key] = '';
}
emptyRow[key] = '';
}
return [...data, emptyRow, totalRow];
}
This will add an empty row and a total with the argument you put as byColumn. You need to be careful about the values you are summing (i.e. add type checking or validate the column name with hasOwnProperty).
I might be a little late, but here’s another question that reminded me that material table happen to have a footer row api.
You can use it alongside a specific method to sum values (or else) that you can call before setting the datasource for example, or on demand.

Angular6 Dynamic Array Filter ( TypeScript )

I have a question about dynamicly filter array.. I making a table and I have different filtering options. For example ; Only selected column filter, MultiSelect dropdown menu filter and ı want filter multiple columns . my table
For Example ;
Write a filter word in Brand filter. This code line is filtered my data. (veri = data. (in Turkish) ).
public filter(str, i) {
const collName = this.bizimKolon[i].Baslik; // Column Name
this.veri = this.yedekVeri.filter(x => x[collName].toString().toLowerCase().includes(str.toLowerCase())); }
I want to filter the filtered data by year but is not working. And I have a more problem. We were suppose filtered Brand and Year. if the filter word we wrote is in the array, update my array and display into table. OK. No problem. We select colors in dropdown menu. After we want filter by colors ( White and Green ). How we make do this? I don't know how many data will come to filter. in this point we need to dynamic filter. Please help me. thank you..
x[colName] should work.
#Pipe({name: 'dataListFilterPipe'})
export class DataListFilterPipe implements PipeTransform {
transform(data: any, col: string, value: string): any {
if (data !== undefined) {
return data.filter(x => x[col] == value);
}
}
}
I created a pipe in which list is filtered and it works. This is in angular 6
here is my example for filtering by many inputs:
applyFilter() {
let custs = this.ch.customers.filter((cust: Customer) => {
return (
((cust.name.toLowerCase().trim().indexOf(this.filters[0]) !== -1) || (!this.filters[0])) &&
((!this.filters[5]) || (cust.user.username.toLowerCase().trim().indexOf(this.filters[5]) !== -1)) &&
((!this.filters[2]) || (cust.state.name.toLowerCase().trim().indexOf(this.filters[2]) !== -1)) &&
((!this.filters[1]) || (cust.description.toLowerCase().trim().indexOf(this.filters[1]) !== -1)) &&
((!this.filters[3]) || (cust.last_mess.toLowerCase().trim().indexOf(this.filters[3]) !== -1))
);
});
this.dataSource.data = custs;
this.ch.customers_filter = this.dataSource.data;
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
Variable Filter is array of string.

ExtJS - Grid filter with multiple columns and multiple values

I create a grid and a toolbar with Two Menu of menuCheckItem. When i check the menuCheckItem the grid filters even with multiple values and multiple columns.
This working fine, as I have created grid 1st and then the toolbar
this.up('') // Used Instead of Ext.getCmp()
Working FIDDLE - https://fiddle.sencha.com/#view/editor&fiddle/2lop
Now I am trying to create same toolbar along with Menu separately on top 1st and then create grid at below. But while doing this, nly Multiple values is working.
I am trying to filter grid with multiple values as well as multiple columns.
Few things i tried -
// Only Filters One Value at a time with each Columns
store.queryBy(function(record,id){
return (record.get('name') == someValue && record.get('phone') == otherValue);
});
and
// Filters Many Columns with Single Value
filter.add(
property : name, phone
value : "somevalue"
operator : "OR"
);
Is there any way to implement Toolbar 1st and then grid ? And Filter grid with many values and columns simultaneously ?
In this FIDDLE i remade a function(checkchange), which is universal , can be put separately and you'll be able to attach it to every menucheckitem you create. The only thing is that if you add new menucheckitem filter you should name the menucheckitem id with the name of the columnDataIndex-Menu and add this columnDataIndex in menuFilters and thats all.
checkchange: function (checkbox, checked, eOpts) {
var menuFilters = ['name', 'phone'];
var getChecked = function (m) {
var checkedItems = [];
m.items.items.forEach(function (c) {
if (c.checked) {
checkedItems.push(c.text);
}
});
return checkedItems;
};
//
var menus = new Map();
menuFilters.forEach(function (e) {
menus.set(e, Ext.getCmp(e + '-Menu'));
});
//
var fieldValues = [];
menuFilters.forEach(function (e) {
fieldValues.push([e, getChecked(menus.get(e))]);
});
//
var store = checkbox.up('grid').store;
store.clearFilter();
//
if (fieldValues.length > 0) {
store.filterBy(function (record) {
var fV = this.fieldValues;
for (var i = 0; i < fV.length; i++) {
if (fV[i][1].length > 0) {
if (fV[i][1].indexOf(record.get(fV[i][0])) === -1) {
return false;
}
}
}
return true;
}, {
fieldValues: fieldValues
});
}
}

AngularJS server-side multi-column search

I am building an application in NodeJS and AngularJS.
I am building a multi-column search functionality where the user can type in search keywords into separate searchboxes (at the top of each column) and retrieve the results based on the column.
So far I have a single searchbox that searches all attributes at the same time.
How can I implement multiple individual searchboxes that will return results based on multiple attributes?
Note: I want to implement this on the server-side for performance reasons. (I know that I can simply use HTML attributes | filter:column1 | filter:column2 but want to avoid this technique if possible).
Here is the code I have so far. I am thinking that I need to pass in some sort of "searchBy" variable that is set on the view and then update the search method to search by multiple query/attribute pairs.
//Search service factory
//Initialize filtered items and get search results
function search(items, query) {
this.filteredItems = $filter('filter')(items, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], query))
return true;
}
return false;
});
return this.filteredItems;
}
function searchMatch(haystack, needle) {
if (!needle) {
return true;
}
return haystack.toString().toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
//Controller
vm.filteredItems = vm.search(vm.unfilteredItems, vm.query);
//View
input(type='text', ng-model='vm.query', ng-change='vm.search(vm.unfilteredItems, vm.query)', placeholder='Search')
I was able to solve this by first creating an array of objects for each search box then repeating those boxes in the view with the ng-repeat attribute.
//Controller
var vm = this;
var vm.unfilteredItems; //data source query removed for brevity
//Initialize search inputs
vm.search_by_inputs = [
{search_column: 'id', search_query: ''},
{search_column: 'requester', search_query: ''},
{search_column: 'dataowner', search_query: ''}
];
function initSearch() {
vm.filtered_items = vm.search(vm.unfiltered_items, vm.search_by_inputs);
}
//View
input.input-large.search-query(type='text', value='{{search_by.search_query}}', ng-model='search_by.search_query' ng-change='vm.initSearch()', placeholder='Search')
The next step is to loop over the search_by_inputs object in the controller and create a new object with only the inputs that have search values entered into the searchboxes in the view. Then in the search method the built-in "filter" component iterates each item, and inside that loop each of the search terms is checked against that value with the column name that matches the property.
/*
* Create new array of objects with only elements that have search values to optimize loop inside filter
* #search_by_inputs array of objects each has a key search_column and a value search_query
*/
function optimizeSearchProperties(search_by_inputs) {
search_by_properties = [];
for (var i = 0, len = search_by_inputs.length; i < len; i++) {
//If this column input box has query text
if (search_by_inputs[i].search_query) {
search_by_properties.push(search_by_inputs[i]);
}
}
return search_by_properties;
}
/*
* #haystack search item
* #needle search term
*/
function searchMatch(haystack, needle) {
if (!needle) {
return true;
}
return haystack.toString().toLowerCase().indexOf(needle.toLowerCase()) !== -1;
}
/*
* Create filtered items object by filtering search results
* #items original array of objects returned by database query result
* #search_by_inputs array of objects each has a key search_column and a value search_query
*/
function search(items, search_by_inputs) {
var search_by_properties = optimizeSearchProperties(search_by_inputs);
//If there are no search properties input by requester then return all items
if (search_by_properties.length === 0) {
this.filtered_items = items;
return this.filtered_items;
}
this.filtered_items = $filter('filter')(items, function (item) {
var search_result = true;
//Loop over all search by input textboxes
for (var n = 0, len = search_by_properties.length; n < len; n++) {
//If there is no query text
if (!search_by_properties[n].search_query) {
//Continue to next element in array
continue;
//Else if element has a property that matches search input column name
} else if (item[search_by_properties[n].search_column]) {
if (!searchMatch(item[search_by_properties[n].search_column], search_by_properties[n].search_query)) {
search_result = false;
break;
}
}
}
return search_result;
});
return this.filtered_items;
}
I would be glad to have some feedback on this solution in terms of optimization, performance, technique, etc. Thanks!

how do I define a nested store for ext.js using ext.net

Platform - Ext.net 2.1 in an MVC project. The data is coming back as json from a DirectMethod and I'm binding on the client.
I'm returning the results of a dataset with multiple tables with relationships defined between the tables. I want to bind the resulting data to a store to be used in a dataview. The first dataview that I'm filling, only uses the highest level of data. However, when the user selects a record in the dataview, I want to bind to another template in a different dataview to provide all levels of information.
Tables
Account
--- Addresses
(I'll skip the other table for now)
Here is the definition of my models and store:
#(Html.X().Model()
.Name("SearchResults.Models.Address")
.IDProperty("nafnmfuid")
.Associations(assoc => assoc.Add(new BelongsToAssociation() {Model = "SearchResults.Models.Account"}))
.Fields(
new ModelField("nafnmfuid", ModelFieldType.Int),
new ModelField("naftype"),
new ModelField("nafadd1"),
new ModelField("nafcity"),
new ModelField("nafstate"),
new ModelField("nafzip")
))
#(Html.X().Model()
.Name("SearchResults.Models.Account")
.IDProperty("nmfuid")
.Associations(assoc => assoc.Add(new HasManyAssociation() {Name = "Addresses", Model = "SearchResults.Models.Address", AssociationKey = "Addresses", PrimaryKey = "nmfuid", ForeignKey = "nafnmfuid"}))
.Fields(
new ModelField("nmfuid", ModelFieldType.Int),
new ModelField("AmfLastNamePrimary"),
new ModelField("AmfFirstNamePrimary"),
new ModelField("nmfid"),
new ModelField("naftype"),
new ModelField("nafadd1"),
new ModelField("nafcity"),
new ModelField("nafstate"),
new ModelField("nafzip")
)
)
#(Html.X().Store()
.ID("StoreSearchResults")
.ModelName("SearchResults.Models.Account")
.Reader(readers => readers.Add(Html.X().JsonReader()))
)
I tried returning the data as nested json as well as three objects in the json.
When I bind the data (on the client), I get the new field in the highest level (Account) called Addresses. However, the field is an empty array.
When I look at the RAW property of the Account record, I see all the nested data.
Here is the ext.js code that's generated by Ext.net
window.App.StoreSearchResults2 = Ext.create("Ext.data.Store", {
model:Ext.define("SearchResults.Models.Address", {
extend: "Ext.data.Model"
, fields:[ {
name:"nafnmfuid"
,type:"int"
}
, {
name:"naftype"
}
, {
name:"nafadd1"
}
, {
name:"nafcity"
}
, {
name:"nafstate"
}
, {
name:"nafzip"
}
]
,idProperty:"nafnmfuid"
,associations:[ {
type:"belongsTo"
,model:"SearchResults.Models.Account"
}
]
})
,storeId:"StoreSearchResults2"
,autoLoad:true
,proxy: {
type:'memory'
, reader: {
type:"json"
}
}
});
window.App.StoreSearchResults = Ext.create("Ext.data.Store", {
model:Ext.define("SearchResults.Models.Account", {
extend: "Ext.data.Model"
, fields:[ {
name:"nmfuid"
,type:"int"
}
, {
name:"AmfLastNamePrimary"
}
, {
name:"AmfFirstNamePrimary"
}
, {
name:"nmfid"
}
, {
name:"naftype"
}
, {
name:"nafadd1"
}
, {
name:"nafcity"
}
, {
name:"nafstate"
}
, {
name:"nafzip"
}
]
,idProperty:"nmfuid"
,associations:[ {
type:"hasMany"
,associationKey:"addresses"
,primaryKey:"nmfuid"
,model:"SearchResults.Models.Address"
,foreignKey:"nafnmfuid"
,name:"Addresses"
}
]
})
,storeId:"StoreSearchResults"
,autoLoad:true
,proxy: {
type:'memory'
, reader: {
type:"json"
}
}
});
The problem was that I was using the method loadData on the client to bind the data. Switching to loadRawData did the trick.

Resources