React-Select isMulti retrieve selected options - reactjs

I'm currently working on a springboot/reactjs project. I'm using the react select library to set a multi select input in one of my forms but I could not get the selected values here's some code to make it a bit clearer.
these are my options generated dynamically from the database each option has the webService Id as a value
this is my select input, I need to get the selected values "Ids" and then call the method that retrieves the webservices from the database and then assign the list of webServices to my newApplicationData.webservices
this is the get web service function

Update : I kind off found a solution to my problem : on the onChange prop I used this
onChange={(selectedOptions) => {
const state = this.state;
state.selectedWebServices = [];
selectedOptions.forEach((option) => {
this.getWS(option.value);
state.selectedWebServices.push(this.state.getWSData);
});
state.newApplicationData.webServices =
state.selectedWebServices;
this.setState(state);
}}
and then I found out another problem: even if I select two deffrent options the list of selected options only gets one duplicated option????!!!!

Related

Angular FormControl's material-checkboxes.component has selected values but this.controlValue is an empty array

I have an Angular form I've built that consists of a single material-checkboxes component. I have two copies of this component, one is static and one is dynamic. The only difference is that the dynamic version gets its control values from an API call. Both of these examples have one or more options defaulted as checked when the controls initialize.
The issue I have is that the dynamic one's model is out of sync with its view as long as its left unchanged (ie, if I don't click on any of the checkbox controls to select or unselect them). Once I click on one of the checkboxes, the model updates to sync with the view.
I can tell this because I can submit the static version and get expected results (the defaulted items are posted as values as expected). However, when I submit the dynamic one, I get an empty post.
Here is what the component looks like with the defaulted values before I submit it to see the submitted form data:
And here is the resulted submitted values (as expected):
By way of comparison, here is the same control (material-checkboxes.component.ts) but built using an external datasource to feed in the titleMap and also has defaulted values.
And here is the result after submit of the above form:
So, as the screencaps indicate, The manually created one works as expected and submits the form containing the defaulted values. However, the component with the dynamically generated values, even though the view shows it to have selected default options, submits as EMPTY.
Expected: this.controlValue = ['12', 'd4']
Actual:
onInit > this.controlValue = ['12', 'd4']
After updateValue method > this.controlValue = undefined // But the view is unchanged from the init
However, I can get it to submit data as expected, if I manually change any of the values, even if i set them exactly as they were defaulted. Its as if the form data is not being set until manually clicking on the options.
Here is a snippet from the template that holds the component:
<mat-checkbox
type="checkbox"
[class.mat-checkboxes-invalid]="showError && touched"
[class.mat-checkbox-readonly]="options?.readonly"
[checked]="allChecked"
[disabled]="(controlDisabled$ | async) || options?.readonly"
[color]="options?.color || 'primary'"
[indeterminate]="someChecked"
[name]="options?.name"
(focusout)="onFocusOut()"
(change)="updateAllValues($event)"
[required]="required"
[value]="controlValue">
Update: I found that the issue was that the form control's value is not updated before leaving the syncCurrentValues() method called just after the setTitleMap hostlistener. Adding a call to this.updateValue() in syncCurrentValues() resolves it and the model and view are back in sync. However, there is a problem, but first, here is the code that resolves the issue when there is a default value set in the this.options data:
#HostListener('document:setTitleMap', ['$event'])
setTitleMap(event: CustomEvent) {
if (event.detail.eventName === this.options.wruxDynamicHook && isRequester(this.componentId, event.detail.params)) {
this.checkboxList = buildTitleMap(event.detail.titleMap, this.options.enum, true, true, this.options.allowUnselect || false);
// Data coming in after ngInit. So if this is the first time the list is provided, then use the defaultValues from the options.
const value = this.setDefaultValueComplete ?
this.jsf.getFormControl(this)?.value || [] :
[].concat(this.options?.defaultValue || []);
this.syncCurrentValues(value);
// Set flag to true so we ignore future calls and not overwrite potential user edits
this.setDefaultValueComplete = true;
}
}
updateValue(event: any = {}) {
this.options.showErrors = true;
// this.jsf.updateArrayCheckboxList(this, this.options.readonly ? this.checkboxListInitValues : this.checkboxList);
this.jsf.updateArrayCheckboxList(this, this.checkboxList);
this.onCustomAction(this.checkboxList);
this.onCustomEvent(this.checkboxList);
this.jsf.forceUpdates();
if (this.jsf.mode === 'builder-properties') {
this.jsf.elementBlurred();
}
}
syncCurrentValues(newValues: Array<any>): void {
for (const checkboxItem of this.checkboxList) {
checkboxItem.checked = newValues.includes(checkboxItem.value);
}
this.updateValue(); // Fixed it. Otherwise, the checked items in titlemap never get synced to the model
}
The call to updateData() above fixes the issue in that case. However, when there are no default values in the options data and the checkbox data is loaded externally from an API call that executes after the ngOnInit has fired, I have the same issue. this.controlValue is empty after ngOnInit despite that the view has updated to show checked checkboxes. The model has made that happen through the setTitleMap() method but the controlValue still logs as an empty array.

Firebase cloud function not updating record

imagine this scenario:
You have a list with lets say 100 items, a user favorites 12 items from the list.
The user now wants these 12 items displayed in a new list with the up to date data (if data changes from the original list/node)
What would be the best way to accomplish this without having to denormalize all of the data for each item?
is there a way to orderByChild().equalTo(multiple items)
(the multiple items being the favorited items)
Currently, I am successfully displaying the favorites in a new list but I am pushing all the data to the users node with the favorites, problem is when i change data, their data from favorites wont change.
note - these changes are made manually in the db and cannot be changed by the user (meta data that can potentially change)
UPDATE
I'm trying to achieve this now with cloud functions. I am trying to update the item but I can't seem to get it working.
Here is my code:
exports.itemUpdate = functions.database
.ref('/items/{itemId}')
.onUpdate((change, context) => {
const before = change.before.val(); // DataSnapshot after the change
const after = change.after.val(); // DataSnapshot after the change
console.log(after);
if (before.effects === after.effects) {
console.log('effects didnt change')
return null;
}
const ref = admin.database().ref('users')
.orderByChild('likedItems')
.equalTo(before.title);
return ref.update(after);
});
I'm not to sure what I am doing wrong here.
Cheers!
There isn't a way to do multiple items in the orderByChild, denormalising in NoSQL is fine its just about keeping it in sync like you mention. I would recommend using a Cloud Function which will help you to keep things in sync.
Another option is to use Firestore instead of the Realtime Database as it has better querying capabilities where you could store a users id in the document and using an array contains filter you could get all the users posts.
The below is the start of a Cloud function for a realtime database trigger for an update of an item.
exports.itemUpdate = functions.database.ref('/items/{itemId}')
.onUpdate((snap, context) => {
// Query your users node for matching items and update them
});

key of the value is undefined with Firebase 4.5.2 and ionic 3

I'am using ionic 3 and firebase 4.5.2 to make an application. I have a project in firebase and I would like to add and delete some values in my list "shoppingItems". I can now retrieve the list view and add items.
Screen of my database
My problem I can't remove a task because the $key of my value is undefined.
I get my list like this :
My values are contained in my variable result ( is an array of the object item: which contain 2 string the value and the key).
Thank's
What version of angularfire2 are you using? I've been attempting to learn Angular and in running through a CRUD tutorial while running on angularfire2 v5.0, I discovered that valueChanges() does not return any metadata.
The following information is gleaned from the angularfire2 documentation located at https://github.com/angular/angularfire2/blob/master/docs/version-5-upgrade.md
Calling .valueChanges() returns an Observable without any metadata. If you are already persisting the key as a property then you are fine. However, if you are relying on $key, then you need to use .snapshotChanges() and transform the data with an observable .map().
The documentation does provide an example as well.
constructor(afDb: AngularFireDatabase) {
afDb.list('items').snapshotChanges().map(actions => {
return actions.map(action => ({ key: action.key,...action.payload.val() }));
}).subscribe(items => {
return items.map(item => item.key);
});
}
Hopefully, you've discovered the solution by now. But I thought I'd drop this here in the event someone else finds your post.

Remove object from a Firebase ListObservable

I'm developing an Angular2 application with Firebase as the datastore. The first step was to use a collection and to push objects into the collection:
this.weeks$ = angularFire.database.list("/weeks");
this.weeks$.push({
id: ScheduleComponent.weekId(),
});
I want now to delete a week from the collection. Do I have to query Firebase for the object and delete it? Or is there a way to delete an object from the ListObservable directly?
Shouldn't be that difficult...
I've tried to query the database, but this deleted the entire collection:
this.angularFire.database.list('/weeks', {
query: {
id: weekId
}
}).remove();
Or do I have to use the filter operator on the ListObservable to get the object and delete it? I'm trying the following:
this.weeks$
.find(week => week.id == weekId)
.do(
week => console.log(week)
// here the delete code
).subscribe();
But without expected results?
What am I doing wrong? I assume it's a combination of not knowing how to work with Firebase Angular 2 binding and not knowing how to properly handle rx observables.
EDIT
I've found a way to delete an object, but I'm still not satisfied with it:
The template looks the following way:
<button class="btn btn-default (click)="deleteWeek(week.$key)">delete</button>
And the code:
this.angularFire.database.object(`/weeks/${weekId}`).remove();
How to delete an object without using it's Firebase key, e.g. on user input? And is it necessary to query again for the object? How to delete the object directly using the ListObservable?
You can remove elements from the list by passing them to remove. For example, this would delete the first element:
this.weeks$ = angularFire.database.list("/weeks");
this.weeks$
.first()
.subscribe((list) => this.weeks$.remove(list[0]));
You can also pass preserved snapshots to remove:
this.weeks$ = angularFire.database.list("/weeks", { preserveSnapshots: true });
this.weeks$
.first()
.subscribe((list) => this.weeks$.remove(list[0]));
You can also pass the push ID/key (which is made available by the thenable that's returned by push) to remove:
this.weeks$ = angularFire.database.list("/weeks");
let key = this.weeks$.push({
id: ScheduleComponent.weekId(),
}).key;
this.weeks$.remove(key);
The key is also available from the item itself:
this.weeks$ = angularFire.database.list("/weeks");
this.weeks$
.first()
.subscribe((list) => this.weeks$.remove(list[0].$key));
(Note that the code in this answer isn't indended to be sensible; it's just here to show how the values passed to remove would be obtained.)

getting selected value for select list in angular from a $firebaseArray()

I have a simple select list that is based on a $firebaseArray(). I dont have a problem getting the values into the drop. Just the selected value.
<select class="form-control" ng-model="vm.selectedRole"
ng-options="role.name for role in vm.allRoles">
</select>
The $firebaseArray looks like this
In my controller the function that initializes the form with the select is
Get.getParentUrl('roles').$loaded()
.then(function (data) {
vm.allRoles = Get.getParentUrl('roles');
vm.selectedRole = entity.role.name;
})
And this populates the select but it does not set the selected value for it on vm.selectedRole. Note that entity is the value that is being passed , so if i write a
console.log(entity.role.name);
The returned value is the selected value that is being passed. So if the user selects a user with a role "Supervisor" and i write a console.log(vm.selectedRole) inside the .then(function(data){ the value returned is "Supervisor"
However the html displays a "?"
I got it working by adding the vm.selectedRole like so
vm.selectedRole = { name: entity.role.name };
Which works i guess. Syntax seems a bit crappy though
https://docs.angularjs.org/api/ng/directive/ngOptions

Resources