Preload already selected items on vue multiple-autocomplete - javascript

Let's say I have a vue-component that is able to store multiple options from a api-fetching-based autocomplete.
Looks a lot like this one but the model (which I think represents the selected entries) is an array and the v-autocomplete has the multiple option. https://vuetifyjs.com/en/components/autocompletes/#api-search
here is the codepen I edited https://codepen.io/cesarbonadio/pen/bGYLMGa?editors=1010
The problem is that I can't get it work when I try to preload already persisted data to that component.
what I currently do:
I pass the data through a prop, then I map it and assign it to the model property of the component.
The problem is that at the first instance, the selected options doesn't show up, only when I do the search inside the autocomplete, which causes the search-string to update.
if I initialize the search string as search: "", then it works, it does a search with the search-string empty, fetching all the elements that matches with "" (in other words, all of them). This is bad performance and it is not ideal because I have like 8 or 9 autocompletes inside the same parent-component.
What I can do to show up the selected options without forcing the empty search?

Related

Why after the changes the list is not displayed and the functional that I need does not work? How to fix it?

I have an object in which the array is located, and using the fetch method I get a data object and then I have a list of factory workers + a filter on the page.
Here is my application code:
https://codesandbox.io/s/sad-bas-ej8l5
But I had to add two buttons, when the first button is pressed, the list of employees which go to the first shift is displayed, and when the second button is pressed, the employees which go to the second shift.
What I added to the code:
1) in the file today.json added the object second (the list of employees of the second shift)
2) added the SecondToday.js file and created the SecondToday component (to display the second shift list)
3) in App.js in state added the defaultTab property with true value and then created two methods that change the state and, depending on this, in the render method, display the FirstToday component (list of first shift workers) or the SecondToday component(list of second shift workers).
But after my changes now the list is not displayed at all ....
Here's a new option:
https://codesandbox.io/s/focused-ellis-wbkyr
How to fix the problem? What have I not done?
Your issue is related to the fact that your .json data file is not correctly formatted as json.
I replaced your json data file with the working one and it now loads correctly.
The 2nd problem of it still not displaying after that is fixed has to do with your data verification check in SecondToday.js. You are checking to see if props.data.group.second exists, but it's undefined. If you log your props, it shows that your second key exists outside of group.

Can I affect properties of an Angular component based on change of other properties in a non-template-driven fashion?

I'm developing a form with Angular 6 and using some standart components, including ng-select (I'd say that's a requirement). The form is supposed to have rather complicated logic (some field values affect other values or suggestions that ng-select should show). I have a rather general question (hoping that there's an approach which I haven't just found yet), but to stay more specific, let's consider the following example:
I have 2 dictionaries (let's call them categories and items), each item being a "child" of a certain category
I have to let user select a category and an item from each dictionary, for that I have 2 fields like
<ng-select
name="category"
[items]="formSuggestions.categories$ | async"
bindLabel="name"
[(ngModel)]="formFields.category"
></ng-select>
<ng-select
name="item"
[items]="formSuggestions.items$ | async"
bindLabel="name"
[(ngModel)]="formFields.item"
></ng-select>
(in fact, they are wrapped into custom components which I omit for simplicity)
(here formSuggestions.items$ and formSuggestions.categories$ are observables that are filled with suggestions on server response; each item is actually an object having id, name and parentId)
what I need is: when a category is selected, suggestions for items are limited to those which are children of that category; when an item is selected, the category is set automatically
My question is: is there a way in Angular to "subscribe" to changes of one property in model (formFields.item) and apply it to others (formFields.category, formSuggestions.categories$) or the only way to deal with this is to set Outputs like (change) of each field?
The problem with that approach is the actual form is more complicated, for instance:
there's another interface that should be shown in a modal window, where user can choose category (and same for item), so there's multiple points which change the props
item selection should affect another ng-select's suggestions (for another field) and pre-fill some crud interface with default stuff for that item
by the way, I have to show only 10 suggestions each time (suggestion dictionaries are quite long) and there's no "limit" option in ng-select, so I have to affect suggestion list based on field value
...
so I really wonder if I can go less template-driven. Any suggestions, at least for the 2 selections case?
(change) is listening to the classical input change event (not Angular specific). See also MDN-Link
For all [(ngModel)] bound elements, you could also use (ngModelChange) to listen to changes. Thats more Angular style. And it gets even more interesting when you create your own "input" components with the ControlValueAccessor.
The problem in your example is, that you use the subscribed suggestionCategories directly. You could (theoreticly) do a "map" in the observable stream and filter out the unwanted values. But this would only work for each emited event of the observable.
So in your case i fear you have to subscribe to the source, store the result in a component local variable. You also copy the data in a second variable that you use to show the values on the UI.
And whenever the user selects a category, you take the original stored data, filter it and assign the filtered result to your second-variable.
HTML
<ng-select
name="category"
[items]="formSuggestions.categories$ | async"
bindLabel="name"
[(ngModel)]="formFields.category"
(ngModelChange)="filterCategorySugestions($selectedValue)"
></ng-select>
In Typescript you would then use the filterCategorySugestions Method to filter the data and write it into your second variable (mentioned above).
by the way, when filtering, you could afterwards apply a mylist.splice(10) (standard Array method) to limit your results to the first 10. But perhaps you should ensure the order first. :-)
I hope it helps a bit.
warm regards
Jan

Vue list doesn't "properly" re-render after being sorted

The sorting logic below is pretty simple:
1. Tags products that doesn't contain selected sorting value
2. Sort products by the amount of selected sorting value in descending order
3. Hide products that doesn't contain selected sorting value
I've added simple sorting logic and it does the trick to sort the elements (can be expected in the console)
Current problem:
The way the list is rendered to the page doesn't actually display newly order, but rather modifies order just of the few items.
Actual code in a Codepen
Can somebody suggest what can be a more efficient way to achieve functionality which will also properly "reposition" elements on the page according to the newly sorting order.
P.S: If you would select iron for example it will be visible that output in the console doesn't match with list items order rendered to the page
The products property which you are iterating in your html code to render the list of products is not an observable. Vue only tracks observable properties and re renders every time any one of the observables changes. Even though you are changing the order of products, Vue is not aware of the change as it is not an observable. To make products property an observable add it in data property just the way you have added nutrients and initialise it as an empty array.
Make your data field something like this:
data: {
nutrients: nutrients,
products: []
}
See this for better understanding of Vue's reactivity system works.

Optionally pass data to child element via directive

I have a popup dialog box that I wish to display one of two slightly different views, dependant on whether I have data present or not.
Is there a way in which I can optionally pass in said data within the directives?
ie. I would like to use something like
<my-comp *ngIf="ifPopup" [data]="myData" [isNew]="isNew"></my-comp>
where the [data] may not always be present, ie. It may either be undefined or have actual data present.
I just want to avoid having to basically duplicate my component.
Update after confusion around my question
Basically I am adding a new record to my DB (imagine adding a new customer etc). My component will either be used to edit a record or create a new record. If I am editing a record, myData will be filled with this record. If I am creating a new record, myData will be undefined..
why don't you just use
<my-comp *ngIf="ifPopup && myData" [data]="myData"></my-comp>
in this way, If the myData is not present, your popup wont display
Or you can also use <ng-container> and wrap your component inside and and use ngIf for your data!

How can I bind the selected text of a Select box to an object's attribute with Knockout JS, or anything else?

I have a select box pull down that I'm populating with a JSON list returned from a stored procedure, but unfortunately when I update the linked object I need to return the selected text of the pulldown, not the selected index like one would think (poor database design, but I'm stuck with it for now and cannot change it).
Does anyone have any ideas what I can do to keep the selected text synced with the appropriate javascript object's attribute?
You could keep both, the value and the text, if you use subscribers.
For instance, if each of your javascript objects look like this:
var optionObject = {
text:"text1"
value: 1
}
Then your binding would look like:
Where 'OptionsObjects' is a collection of optionObject and selectedOption
has two observable properties: text and value.
Finally you subscribe to the value property of the selectedOption:
viewModel.selectedOption.value.subscribe(function(newValue){
var optionText = viewModel.OptionsObjects[newValue].text;
viewModel.selectedOption.text(optionText);
});
Then if you want to see the new selected option text when the value is changed,
you could have a binding as follows:
<span data-bind:"text:selectedOption.text"></span>
In your particular case you would return selectedOption.text().
So yes, you got what I was getting at. Use the text as the value for the select options rather than using an index. The value really should be something useful, I can't think of any case where I've ever used an index. A number sure, but a number that relates to the application's models in some way (like an id from a database), not to the number of items in the select box.
Well done.

Categories

Resources