Angular 6: retrieve data from SelectionModel - arrays

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[];

Related

Mat-select doesnt display the array content in ngfor

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.

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!

Why can't I update its element value correctly within Array.forEach() loop in Angular 7?

I'm testing Material Table(mat-table) on Angular 7, here's a weird issue I ran into.
Send a request to jsonplaceholder for fake data in users.service
export class UsersService {
API_BASE = 'https://jsonplaceholder.typicode.com/users';
constructor(private http: HttpClient) {}
getUsers(): Observable<object> {
const url = this.API_BASE;
return this.http.get(url);
}
}
Because jsonplaceholder only returns 10 rows of data, so I concatenate the data for a larger array, say, 30 rows for testing pagination feature with ease. Meanwhile, update the 'id' field with iterate index so the 'id's looks like 1,2,3...30, instead of 1,2,3...10,1,2,3...10,1,2,3...10, which is a result of concatenation, that's it, nothing special.
users.component:
ngOnInit(): void {
this.userService.getUsers().subscribe((users: UserData[]) => {
users = users.concat(users, users);
users.forEach((user, index) => (user.id = index +1));
console.log(users);
this.dataSource.data = users;
});
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
Although the table shows up beautifully, but the 'id's column looks weird, they are not 1,2,3...30 sequentially, instead, they are 21,22,23...30,21,22,23...30,21,22,23...30
I tried to print out the user.id inside the forEach loop, it's all good.
users.forEach((user, index) => {
user.id = index + 1;
console.log(user.id);
});
Where did I go wrong with this? Any clue? Thanks.
P.S, API used in the code: https://jsonplaceholder.typicode.com/users
even though you have 30 array elements after concatenating the array twice, you still only have 10 unique objects. the Object behind users[20] is the same as users[0], so you override the id of the already processed objects from index 10 to 29
you can fix this by creating a copy of each object. There are many ways too do this. a very simple way is serializing and deserializing using JSON.stringify and JSON.parse:
users.forEach(user => users.push(JSON.parse(JSON.stringify(user))));

Array.filter() in Angular 2 Component

In one component I can filter my array using the following:
// Array of product objects
const result = products.filter(p => p.name.includes('val'));
and value of products remains same as the first value but filtered value stores in result.
But in the following code, filter() filters array of strings itself:
// Array of strings
const result = strs.filter(s => s.includes('val'));
The question is how can I filter strings and return result without modifying the strs itself?
Note: I tried with array.filter(function() { return res; }); but didn't make any change.
It returns the filtered ones and don't change the actual array. You are doing something wrong
const strs = ['valval', 'bal', 'gal', 'dalval'];
const result = strs.filter(s => s.includes('val'));
console.log(strs);
console.log(result);
First thing we need to know is, if we filter our list we loose our original data
products: any[] = [
{
"productId": 1,
"productName": "foo-bar",
"price": 32.99
}
]
and can't get it back without re-getting the data from it's source so we have to make another list to store the filtered list.
filteredProduce: any[];
Next if you are working to show a list of filtered product on a grid or something like this we need a way to know when the user changes the filter criteria. we could use event binding and watch for key presses or value changes, but an easier way is to change our _listFilter property into a getter and setter, like this
get listFilter: string {
return this._listFilter;
}
set listFilter(value:string) {
this._listFilter= value;
}
next we want to set our filteredProducts array to the filtered list of products like this
set listFilter(value:string) {
this._listFilter= value;
this.filteredProducts = this._listFilter? this.performFilter(this._listFilter) : this.products;
}
in preceding code we are using js conditional operator to handle the posibility that _listFilterstring is empty, null or undefined.
Next we use this.performFilter(this._listFilter) to filter our list.
performFilter(filterBy: string): any[] {
filterBy = filterBy.toLocaleLowerCase();
return this.products.filter((product: any) =>
product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
}
Finally we should assign the main list of products to the filteredProducts and _listFilter to what we want.
constructor() {
this.filteredProducts = this.products;
this._listFilter= 'foo-bar';
}
last step is to change our template to bind to our filteredProducts property.

How to select value inside an object

I'm trying to store 1 or more values that are inside an array into a scope. This is the result of my JSONP service,
angular.callbacks._7({
"id":157336,"results":[
{"id":"53db3c790e0a26189a000d09","iso_639_1":"en","key":"ePbKGoIGAXY","name":"Trailer 3","site":"YouTube","size":1080,"type":"Trailer"},
{"id":"550df44b9251413554004d43","iso_639_1":"en","key":"KlyknsTJk0w","name":"Own it today","site":"YouTube","size":720,"type":"Trailer"},
{"id":"533ec6fcc3a3685448009ccc","iso_639_1":"en","key":"nyc6RJEEe0U","name":"Teaser","site":"YouTube","size":720,"type":"Trailer"},
{"id":"5376ab510e0a26141c0005a8","iso_639_1":"en","key":"zSWdZVtXT7E","name":"Trailer","site":"YouTube","size":720,"type":"Trailer"},
{"id":"545da247c3a3685362005187","iso_639_1":"en","key":"Lm8p5rlrSkY","name":"Trailer 2","site":"YouTube","size":1080,"type":"Trailer"}
]
})
And I'm trying to store all the key values inside a scope called $scope.youtubeTrailer
But if I do it like this,
$scope.youtubeTrailer = response;
console.log ($scope.youtubeTrailer)
The scope consists of an object (the movie) and inside that object is an array with the 5 id's. So what would be the correct selector for something like this?
If I search like this,
console.log ($scope.youtubeTrailer.key)
I get an 'undefined´
* EDIT *
I've tried to solution below,
movieAdd.trailer(movie.id)
.then(function(response){
$scope.youtubeTrailer =[];
console.log ($scope.youtubeTrailer)
angular.forEach(response.results, function(item){
console.log ('Hello world')
if (item.hasOwnProperty('key')) {
$scope.youtubeTrailer.push(item.key);
}
});
The console.log ($scope.youtubeTrailer) shows that the scope is empty. And the forEach function doesnt fire because the Hello log doesn't get shown in the console. If I change $scope.youtubeTrailer =[]; into $scope.youtubeTrailer = response; I do have the object in the scope but still the forEach doesn't fire.
* EDIT 2 *
By changinge response.results into response the forEach does fire.
* EDIT 3 *
I've got it somewhat working. I was getting the array in the scope, but when I saved the scope value in the create function it showed as null in the database. That's because I was trying to save an array. Using javascripts join I converted the array to a string which can be saved.
movieAdd.trailer(movie.id)
.then(function(response){
$scope.youtubeTrailer = [];
angular.forEach(response, function(item){
if (item.hasOwnProperty('key')) {
$scope.youtubeTrailer.push(item.key);
var youtubeArray = $scope.youtubeTrailer
var youtubeString = youtubeArray.join();
The code below basically is looping through the response.results array, which contains 5 objects. Each oject is assigned to the variable item. Check item has property of key, if true, add the value of item.key to $scope.youtubeTrailer.
$scope.youtubeTrailer =[];
angular.forEach(response.results, function(item) {
if (item.hasOwnProperty('key')) {
$scope.youtubeTrailer.push(item.key);
}
});
Here is the link for Angular ForEach.
$scope.youtubeTrailer isn't just an object, it contains an array and its inside that array that the key field is. So, you're going to need to access the five interior items with an array access. e.g. $scope.youtubeTrailer.results[0].key

Resources