Mat-select doesnt display the array content in ngfor - arrays

I have an array of countries and i want to display in a mat-select list of options. I am receiving the data like an object format in this.lngCountries so i need to convert to array first.
I think that the array is not complete before the ngfor is loaded. How can I wait for my function to finish? Because my problem is that when the page loads the ngfor my array is still empty.
My code:
private preparePaisOpts() {
let array = this.lngCountries;
this.paisOps = Object.keys(array).map(function(index) {
let count = array[index];
return count;
});
}
HTML:
<th2-mat-select class="form-field-dark" required [form]="usecaseForm"
formControlFieldName="pais"
placeholder="País">
<mat-option *ngFor="let country of paisOps" [value]="country">{{country}}</mat-option>
</th2-mat-select>
Thanks!!! <3

One way is ngIf
<th2-mat-select *ngIf="paisOps && paisOps.length > 0" class="form-field-dark" required [form]="usecaseForm"
formControlFieldName="pais"
placeholder="País">
<mat-option *ngFor="let country of paisOps" [value]="country">{{country}}</mat-option>
</th2-mat-select>
Better is to show a loading spinner instead of the select as example for a better user experience.
You can set a custom variable, too:
loading: boolean = true;
...
private preparePaisOpts() {
let array = this.lngCountries;
this.paisOps = Object.keys(array).map(function(index) {
let count = array[index];
return count;
});
this.loading = false;
}
and HTML
<th2-mat-select *ngIf="!loading" class="form-field-dark" .......
But!
Normally ngFor will be refresh the data if it's array changing. You write not specific error so I don't know what your problem is.

Related

Angular 6 dynamic checkboxes keyvalue return array of IDs

I have a list of dynamic checkboxes using keyvalue pipe that returns objects rather than just array of selected IDs.
can anyone help pls, I need the form to submit just an array of selected user IDs.
https://stackblitz.com/edit/angular-ciaxgj
EDIT
here's the log of a similar form with a multi-select (countries):
console log
I need users (checkboxes) to return an array like countries (multi-select) as in the log above.
Change your OnSubmit function to
onSubmit() {
console.log(this.userForm.value);
var usersObj = this.userForm.value.users;
var selectedUserIds = [];
for (var userId in usersObj) {
if (usersObj.hasOwnProperty(userId)) {
if(usersObj[userId])//If selected
{
selectedUserIds.push(userId);
}
}
}
console.log(selectedUserIds);
}
Here is updated code
https://stackblitz.com/edit/angular-9fd17t
If you want to submit as a Form then add a hidden field to form
<input type="hidden" name="selectedUserIds" value=""/>
set value selectedUserIds from onSubmit and submit the form code.
So, it happens that I have been overthinking the solution in thinking that like the multiselect, checkboxes would/could return a ready array of selected items.
The rather simple solution was from reading another of Eliseo's posts combined with Jaba Prince's answer:
onSubmit() {
var usersObj = this.userForm.value.users;
var selectedUserIds = [];
for (var userId in usersObj) {
if (usersObj.hasOwnProperty(userId)) {
if(usersObj[userId])//If selected
{
selectedUserIds.push(userId);
}
}
}
let data = {
users: selectedUserIds
}
console.log(data);
// post data in service call
}
Many thanks to you two!

Angular 6: retrieve data from SelectionModel

I have a component which has a mat-table with checkboxes using SelectionModel. Here is the code I have to retrieve the data selected.
fileSelect = new SelectionModel<FileInfo>(true, []);
This method is invoked in ngSubmit of the form.
sendFileInterrupt() {
let selectedFileIds: string[];
for (let item of this.fileSelect.selected) {
console.log(item.fileId);
selectedFileIds.push(item.fileId);
}
The selected fileId is logged in console, but when trying to add it to the selectedFileIds array, I'm getting an error
Cannot read property 'push' of undefined
Do I have to instantiate or initialize the array before pushing data into it ?
You need to initialize let selectedFileIds: string[] = [];
sendFileInterrupt() {
let selectedFileIds: string[] = [];
for (let item of this.fileSelect.selected) {
console.log(item.fileId);
selectedFileIds.push(item.fileId);
}
You don't need to iterate through this.fileSelect.selected, it is already an array of rows rows[];

How can I check the size of an array observable?

I’m working in an angular 6 application and I need a way to tell if my 2D observable array is empty or not.
Here’s my template:
<div *ngFor="let 1DArray of 2DArray$ | async">
<div *ngFor="let item of 1DArray">{{ item.id }}</div>
</div>
This gives me a list of ids.
Here’s my component code:
this.allItems$ = [];
source.forEach(obj => {
const colRef$ = this._firestoreService.colWithIds$(`Collection/${obj.id}/SubCollection`); // a collection of items
this.allItems$.push(colRef$); // an array of collections (2D array)
});
this.2DArray$ = Observable.combineLatest(this.allItems$); // an observable of the 2D array
This gives me an observable of the 2D array.
My problem is that if there are no items to retrieve from the firebase collection, the 2D array will not be empty. Instead, it will consist of a bunch of empty 1D arrays:
[
[],
[],
…
]
I’d like to put a label above the list of items on the page, something like “ITEMS:”. But if there are no items, I’d like to suppress this label.
I could do this by setting a flag, something like itemsExist: boolean. I’d set it like this:
this.itemsExist = false;
this.allItems$ = [];
source.forEach(obj => {
const colRef$ = this._firestoreService.colWithIds$(`Collection/${obj.id}/SubCollection`); // a collection of items
if (colRef$.length > 0) {
this.allItems$.push(colRef$); // an array of collections (2D Array)
this.itemsExist = true;
}
});
this.2DArray$ = Observable.combineLatest(this.allItems$); // an observable of the 2D array
…and then wrap the list in the template with a *ngIf:
<div *ngIf=“itemsExist”>
ITEMS:
<div *ngFor="let 1DArray of 2DArray$ | async">
<div *ngFor="let item of 1DArray">{{ item.id }}</div>
</div>
</div>
<div *ngIf=“!itemsExist”>
There are no items to display.
</div>
But I can’t use .length on an observable. There’s no way that I know of to check how many items exist on an array observable. Except, of course, if you subscribe to it. Then you just get the array and you can check it’s length. I tried something like that:
this.allItems$ = [];
source.forEach(obj => {
const colRef$ = this._firestoreService.colWithIds$(`Collection/${obj.id}/SubCollection`); // a collection of items
this.allItems$.push(colRef$); // an array of collections (2D array)
});
this.2DArray$ = Observable.combineLatest(this.allItems$); // an observable of the 2D array
this.itemCount = 0;
this.2DArray$.subscribe(item2DArray => {
item2DArray.forEach(item1DArray => {
this.itemCount += item1DArray.length;
});
});
Then I check itemCount in an *ngIf.
But then my list doesn’t show up at all even when there are items in it. I also tried subscribing to colRef$ and checking the length of the 1DArray, adding it to allItems$ only if it was greater than 0, but that had the same effect. Can an observable still be used in an *ngFor loop after it’s been subscribed to?
What way is there to check the length of an array observable?
You can achieve this with | async pipe.
Example:
<div *ngIf="(2DArray$ | async)?.length !== 0">...</div>
the mat dataSource is a plain ol typescript object so i created a getter called getCount and in the dataSource have a member variable that exposes the response length. Then on the paginator i simple set the [length] to the dataSource.getCount().

Is it possible to make ng-repeat delay a bit redrawing of array content

I'm using ng-repeat to (guess) put array content in table.
Content is drawn dynamically, and it works well, when I'm modifying single elements of an array. But when I reload a whole array, there is this moment, when array is reassigned with new value, and ng-repeat draws blank table (which is actually logically correct). Is there a way to delay redrawing of content that way, the ng-repeat ignores the moment when the array is empty? Like the content is switched to new content without the 'clear' time.
I'm assigning new elements to array this way:
items = newItems;
where items is the array ng-repeat uses and newItems is an array of items freshly downloaded from database. The newItems is complete, when the assignment occurres. I'm not doing items = []; before the assignemt.
I'm usign angular 1.3
EDIT:
the ng-repeat:
<tr ng-repeat="order in submittedOrders">
stuff
<\tr>
js:
`$scope.reloadView = function() {
$scope.submittedOrders = OrdersService.getOrdersByStatus(ORDER_STATUS.submitted);
};`
Can it be the that the table is cleared in the first place, before call to database(service takes data from database) and during the wait, the table is cleared?
You may have to make use of Observables and async pipe of Angular.
Here are few steps you can take:
Convert your newItems to a rxjs Subject.
newItems$ = new Subject();
Whenever you get new values for your array, emit them via subject.
this.newItems$.next(newItems);
Make the items an observable of newItems$, and filter out empty arrays.
items = this.newItems$.pipe(
filter((a:any[]) => {
return a.length != 0;
})
);
In your template, use async pipe to iterate over array.
*ngFor="item of items | async"
Below is relevant parts of code that can get you started.
import { Observable, of, from, Subject } from 'rxjs';
import { filter, mapTo } from 'rxjs/operators';
...
newItems$ = new Subject();
items = this.newItems$.pipe(
filter((a:any[]) => {
return a.length != 0;
})
);
...
// A test method - link it to (click) handler of any div/button in your template
// This method will emit a non-empty array first, then, after 1 second emit an empty
// array, and then, after 2 seconds it will emit a non-empty array again with updated
// values.
testMethod() {
this.newItems$.next([3,4,5]);
setTimeout((v) => {
console.log("Emptying the array - should not be displayed browser");
this.newItems$.next([]);
}, 1000);
setTimeout((v) => {
console.log("Updating the array - should be displayed in browser");
this.newItems$.next([3,4,4,5]);
}, 2000);
}

AngularJS: searching data client side by custom filter

i am learning angular. so i am not good in angular. i am showing data in tabular format with the help of ng-repeat. i have one dropdown and textbox for filter data showing by ng-repeat. fields name are populated in dropdown. so user will select field name and put corresponding value in textbox and search will perform accordingly and data will be shown.
my code is working partially. basically some kind of problem is there in SearchList function. the problem is when trying to search by id then SearchList is not working properly. so looking for help. what to fix in the code. my js fiddle https://jsfiddle.net/tridip/rnoo3bqc/6/
$scope.SearchList = function(row) {
if ($scope.selectedFieldName && $scope.searchText) {
var propVal = row[$scope.selectedFieldName.toLowerCase()];
if (propVal) {
return propVal.toUpperCase().indexOf($scope.searchText.toUpperCase()) > -1;
} else {
return false;
}
}
return true;
};
working version url
https://jsfiddle.net/tridip/rnoo3bqc/8/
You need to convert the id's from number to string, e.g. by concatenating an empty string:
var propVal = row[$scope.selectedFieldName.toLowerCase()] + '';
the problem was with id that's a numeric field and hence toUpperCase() was failing for it.
if (propVal) {
propVal.toString().toUpperCase().indexOf($scope.searchText.toUpperCase()) > -1;
} else {
return false;
}

Resources