I have a situation here, the valueChanged gets called even if I change the bindable property value internally within custom element. How do I send the updated value back to viewModel from custom element without triggering valueChanged for that bindable value.
is there a way to supress this? or I have to use internal tracking if this is called from internal code or coming from view?
There is no way to prevent a bindable property's change handler method from being called based on whether the custom element's own code is assigning the property or whether it's being assigned by external code or in response to user input. You will have to roll your own internal tracking mechanism.
As Jeremy said, there's no way to prevent a bindable property's change handler from being called. However, you could attach or trigger your code only with the form input using the change.delegate or keyup.delegate properties. That would allow you to isolate your event code from the changes resulting from binding properties.
Here's a GistRun to demonstrate this:
https://gist.run/?id=11cd1e90dd912f07a60afaedb9c2613b
Related
I need to detect a change in a form's field, as I understand in Vue there are two ways to do that:
via v-on directive
via watch method
Which one would you recommend to use? Are they the same in terms of how much memory they use? Why would I prefer one to the other?
UPDATE
Just to explain what I need: I have a form and I need to send a Google Analytics ga event out each time somebody enters something in the field and then leaves it. v-on or watch?
You understand incorrectly. Use v-on to detect events like change or input on a form field. Use watch to detect changes in a reactive data item (data, computed, or prop).
If you use v-model on a field, you are implicitly using v-on to detect input (or change if using the .lazy modifier) and copy that value into a data item. If you are tempted to add another v-on to detect changes, you probably should watch the data that is already changing with the form field. The exception is if you specifically need to know that the change came from the form field and there might be other ways it could change.
I have an custom component that serves as an input (in my application it does more things, but I've wanted to keep same structure so I've wrapped native input into component).
Then when user changes value of an input, I am calling closure action to format value provided by user (in example I am uppercasing it) and set it to some property (which should be visible for user in input).
Problem happens when I paste some lowercased string (for example abc), and then without deleting nor adding anything I just select everything and paste from clipboard (again abc). At second paste the formatting closure action is called, even setter of an property is called (I've tried computed property with custom set), but my component's input stays unformatted.
I've provided minimal Ember Twiddle to play with: https://ember-twiddle.com/5448bb455fd8732cc87f6ed8f2d44c12
The value is updated in action handler of application controller. At that handler, toUpperCase is called and result is set to a.
In the second call, since the a is not changed, value of my-input will not changed. So the component will not re-render. And pasted value will stay remained.
You can watch this situation by adding {{log (concat 'test' a)}} line to the application.hbs. It will printed only one time.
To make it work: Put the making uppercase logic to the my-input component. It will simply work. Have a look at this twiddle, you can implement similar component.
I have a custom element being used inside React. I want to be able to change attributes on the element from React. I also want to be able to change the same attributes from inside the element itself. Unfortunately, when the element changes its own attribute, this causes some odd side effects that I believe are related to React's virtual DOM being unaware that the attribute has changed.
To illustrate, assume we have a React render function that returns the following:
<my-component foo="bar"/>
And my-component has logic inside of it that, when the element is clicked, will change foo's value from bar to unicorn. Everything up to this point works as expected. The problem is that during the next render cycle, foo is not set back to bar. I want foo to be set back to bar.
My guess is that React's virtual DOM has bar as the cached value (it doesn't realize it has changed to unicorn) and therefore doesn't attempt to set it back to bar.
Is my understanding correct?
How do I make it so foo's value is set back to bar on the next render cycle?
You are correct about the virtual DOM. To make it behave the way you want, the custom element needs to be written in a way that supports it.
Think of this as being equivalent to controlling an <input>, where you would bind a handler to the input's onChange and either call event.preventDefault() to block any changes to the vlaue, or pass the new value back to the <input> to update the virtual DOM.
Therefore for this to work, the custom element needs to support a similar event handler.
I often need to register a single-purpose event listener to multiple HTML elements (e.g. change, click), in a loop.
I need a way to differentiate between the target elements when the event fires. Ideally the listener should have a variable that changes depending on which element fires the event.
A straight-forward solution would be to set the id attribute in the loop (jsfiddle), and refer to this.id within the handler. Or if additional fields are required, the data-* attributes, and instead accessing this.dataset.id.
However these end up adding to the actual markup of the page, and can only store strings. If you have a lot of data to assign, of specific types other than string, it can be impractical, and require unnecessary type checking, or integer parsing.
I got around this by defining a new property called param on each HTML element, and I could access it in the handler like so: this.param.address. But that turns out to be a bad idea - a 'feature' not to be relied on due to browser consistencies and a lack it being in any standard.
Another way is supplying arguments to the listener through a closure (jsfiddle). The downside of this method is that it returns a unique listener for each element, which might affect performance versus just a single handler.
Yet another method I had thought of was storing the actual element references with data in an array, and performing a lookup of this from the event handler (JSFiddle).
So my question is: Is there a better (and correct/future-proof) way to pass/assign data to element event handlers, without having to store it as an attribute string?
P.S. I don't want to have to rely on jQuery for this either.
With jQuery it's possible to use $(el).bind("click", {foo:i}, buttonClicked) and $.data(el, "param", {foo:i}) to accomplish the task. However it seems to rely on being able to set a custom property to the element's object, much what I proposed for using param as a custom property for my purposes. Does that mean it's fine as long as the property name is unique enough?...
Using the latest knockout 3.3.0 and jquery 1.11.0, any changes made to an input element from JS will not update observables bound to that element via textInput or value.
Example mock code:
html
<input id="test" type="text" data-bind="textInput: testObs" />
js
$("#test").val("someVal");
Example fiddle:
http://jsfiddle.net/whxj5Lf6/
Is there a workaround to this so that such changes will be caught?
Knockout listens for events to know that the value has changed. Specifically it will respond to the change event, which is easy to trigger with jQuery:
$("#test").val("test2").change();
http://jsfiddle.net/mbest/whxj5Lf6/2/
When interfacing with external components, it's often better to use a custom binding rather than the built-in value or textInput bindings. For example, here's a custom binding for use with the jQuery UI datapicker.
According to knockoutjs documentation, the value of an observable will update when the change event will occur.
Whenever the user edits the value in the associated form control, KO
will update the property on your view model. KO will always attempt to
update your view model when the value has been modified and a user
transfers focus to another DOM node (i.e., on the change event), but
you can also trigger updates based on other events by using the
valueUpdate parameter
There is only one valueUpdate parameter exists that matches the criteria of your problem. The input parameter but it has some limitations according to documentation...
"input" - updates your view model when the value of an or
element changes. Note that this event is only raised by
reasonably modern browsers (e.g., IE 9+).
So, I think the best choice for you is to take the solution provided by Michael Best, trigger the change() event manually as following...
$("#test").val("test2").change();