Ask
How to implement a two-way link from an object to a VM in aurelia.io without losing the functionality of Select2 and maintaining the full link of the original, and also that the changes in the VM are reflected in the Select2 .
Context
I am working on a project where the aurelia.io library has been implemented, while the Select2 plugin is being implemented at various points in the project ; the problem is that when initializing the plugin it replaces the dom of theby a series of divs and other objects, thus losing the binding with theoriginal, which remains hidden from view, while working with the newartificial created by the Select2 plugin .
UPDATE 1
This is an example of what you want to achieve.
HTML code:
<label>Seleccione la línea a la que pertenece la sublínea</label>
<select value.bind="sublinea_seleccionada.LineaId">
<option repeat.for="linea of Lineas" value.bind="linea.Id" selected.bind="$parent.sublinea_actual.LineaId == linea.Id">${Linea.Nombre}</option>
</select>
<button click.delegate="asignarLineaPorDefecto()">Seleccionar línea por defecto</button>
TypeScript code:
export class Sublineas{
Lineas: linea[] = [];
sublinea_seleccionada: subLinea = new subLinea();
mostrarIdLineaSeleccionada() {
alert(`Se ha seleccionado la Línea con Id ${this.sublinea_seleccionada.LineaId}`);
}
asignarLineaPorDefecto(){
this.sublinea_seleccionada.LineaId = 1;
}
attached() {
var self = this;
$("select").on("change", event => {
self.mostrarIdLineaSeleccionada();
});
$("select").select2();
}
}
UPDATE 2
I have found this answer on SOen , but in the example provided Select2 only works in one-way, that is, it only updates the value in the view model but it does not update with the changes in it.
Why is the value in the view-model not updated? This library has certain similarities to other libraries that are also used
bind
in models, for example, Backbone. Both Backbone and Aurelia "recognize" when a value change has been made in any of their attributes since they subscribe to events such as "input" or "change" depending on the type of html element, and therefore, it is there where sync the changes with theview
. In your case, that's the only detail missing. But before getting into the solution, we must know some important details of the select2 library that affect the functioning of the Aurelia binding.Drawbacks of select2 .
As you have stated, the select2 library prepends a series of html elements that are intended to render their own design. Despite this, select2 manages to display the value of the original element
<select>
and this can be confirmed on form submission. However, you lose an important factor by prepending this design, and that is that the events ofclick
andchange
are no longer fired on the original element. What does this mean? Here is an example:Let's add the ordinary
listener
event :change
By executing the previous code in the browser, we can confirm that every time an option is selected, it shows us the new select value on the console. Ok, now we add to the select2 library:
Goodbye events! Every time we select an option, nothing happens. It no longer shows the selected value in the console. That's because select2 doesn't dispatch such events on the original element.
Why is the original bind of the
<select>
?It doesn't really get lost, and as said above, select2 is just another component referenced by the initial value of the
<select>
. So, every time we load the page, what is produced is aone-way
bind, since in effect, select2 recognizes the initial value according to the model's bind, but a flow will never be producedview > view-model
, because the change events are never dispatched, and therefore, Aurelia never notices the new value of the<select>
.Finally the solution
There are two missing puzzle pieces for (1) two-way sync
two-way
and (2) without losing select2 functionality:Dispatch the event
change
programmed on the element<select>
in question so that Aurelia does the rest. We do that withclase.lanzarEvento(e.target)
:With the line
clase.lanzarEvento(e.target);
we are manually triggering a "change" event on the<select>
original. The following code contains the event definition:At this point, Aurelia has been notified and thus will end up complementing the bind with a stream
view > view-model
as it will extract the value found in the element and update it to the model.You will notice that in the example above, clicking on the "Select Nissan" button does not update the select2 component. This is because, as we know, it is a component that does not have any bind, since the bind is directly associated with it (as it should be). So how do we solve it? Unfortunately the tool
plnkr.co
does not allow me to push beyond the used demo, because it does not have the module enabledObserverLocator
that solves this issue. With this module we can know when a change has been made on a certain attribute. In other words, the flow would be as follows:However, here I leave the reference code, at least the specific changes on what I just mentioned:
conclusion
I know the answer is very broad, but there were details I didn't want to gloss over, especially since I wanted to illustrate how and when a bind
one-way
and occurredtwo-way
.Bind an object to a Select2 option?
I have a Select2 form like this:
With which I can access
selectedStuff
, which is an array of the ids of the things I've selected. However, I would like to get an array of those things and not their ids. In my use case, it is not feasible to fetch something from its id.Is there a way to force the element object to give me an array of the things I need instead of an array of their ids?
Response:
The element attribute value
<option>
only accepts strings. Use the attribute model to store the non-string elements:Here is a working plunker :
Here is the related documentation on aurelia:
Related questions: