Trigger a model update from view in Angularjs - javascript

If the view (e.g the value in a text input) is changed by an external javascript, it will not be reflected in the model.
How can I trigger a model update (to read back all binding values from the view).
P.S: for some reasons, manually setting the model value is not an option for me, I just need to call the same function that is called when user is typing in the text box.

If you are changing the value of an element, for example input, that uses ng-model it should suffice to trigger the element's 'change' event.
jQuery:
$('#input').val('new value').trigger('change');
No jQuery:
var input = document.querySelector('#input');
input.value = 'new value';
var event = document.createEvent('HTMLEvents');
event.initEvent('change', true, false);
input.dispatchEvent(event);
Demo: http://plnkr.co/edit/IFb8OmegaGAAniy9ttn5?p=preview

Related

How to get change event after js changes a value without modifing existing code

an input field changes its value via jquery (not by a human action), like this:
$("#code").val(9); .
How can I intercept the change event (or similar) without changing or add new lines to code that changes its value.
Programmatically setting value does not trigger any user events so you must trigger one yourself after the new value is set.
I used a change event but you could use others like the "input" event
$("#code").on('change', function(){
console.log('changed value =', this.value);
});
$("#code").val(9).change();
// or
// $("#code").val(9).trigger('change');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="code"/>

Manipulating Select element on form

I'm trying to programatically autofill my information on a form like this (Stripe's testing form) however I'm having trouble filling/selecting some of the fields.
For example, merely changing the Node's value attribute is not working for fields like the cardNumber field, and changing the selectedIndex attribute for the country does not have any effect.
Example:
selectedIndex = 40 from another index like 3 gives you Canada, which when done manually, will cause a Postal Code field to appear. However, I'm having trouble achieving this programmatically by just changing theselectedIndex
You can manually dispatch an event:
var select = document.getElementById('billingCountry')
select.dispatchEvent(new Event('change', { 'bubbles': true }))

How can I get the new value of HTML colorpicker when it changes?

I'm developing a web app that needs to change colour of HTML canvas based on the values of colorpicker.
I have a colorpicker in HTML that I need to get value from every time it updates.
<input type="color" value="#ff0800" id="color">
Currently, this is the code that is associated with the colorpicker in my javascript file.
var backRGB = document.getElementById("color").value;
I am really not sure how this can be achieved.
I have tried other stack exchange question but none of them really meet my requirements so I would really appreciate if someone could show me how this can be achieved.
Adding to the answers already given, We can also attach oninput event handler instead of onchange event. This is another way we can monitor the color picker events from the user.
This event is similar to the onchange event. The difference is that the oninput event occurs immediately after the value of an element has changed, while onchange occurs when the element loses focus, after the content has been changed. The other difference is that the onchange event also works on elements. Here is an example:
const backRGB = document.querySelector(".backRCB");
const color = document.querySelector(".color");
color.addEventListener("input",(event)=>{
backRGB.style.backgroundColor = color.value;
// You can also do it with the event object as event object holds the value of the current color
// backRGB.style.backgroundColor = event.target.value;
});
Hope that would be helpful to many users.
You just need to update the value of backRGB variable when the colorpicker value is changed.
To achieve that, you need to attach a handler to the onchange event of your colorpicker:
document.getElementById("color").onchange = function() {
backRGB = this.value;
}
Demo:
This is a working demo:
var backRGB = document.getElementById("color").value;
document.getElementById("color").onchange = function() {
backRGB = this.value;
console.log(backRGB);
}
<input type="color" value="#ff0800" id="color">
Solution with pure javascript:
//listen to the "change event" attached to your color input
document.getElementById("color").addEventListener("change", onChangeColor);
function that get fired after the input value change:
function onChangeColor() {
console.log(this.value); //this.value contains the hexadecimal value of your input
//change your canvas color
}
to change the canvas color check here

CodeMirror on change failing

I am creating two code mirror instances from text areas in my form, and I need those hidden text areas to be updated before submission. I have added on on change event to the script but it doesn't seem to work.
can anyone help?
Thanks
<script type="text/javascript">
function editor(id) {
var editor = CodeMirror.fromTextArea(id, {
continuousScanning: 500,
lineNumbers: true
});
editor.setSize(900, 600);
}
var config_id = document.getElementById('id_config')
var config = editor(config_id);
var remote_config_id = document.getElementById('id_remote_config')
var remote_config = editor(remote_config_id);
config.on('change',function(cMirror){
// get value right from instance
config_id.value = cMirror.getValue();
});
remote_config.on('change',function(cMirror){
// get value right from instance
remote_config_id.value = cMirror.getValue();
});
</script>
You can't use the change event for that: CodeMirror listens to changes of the hidden text area, so changing the value would fire another change event. That could cause endless loops.
The documentation contains the correct approach:
the library provides a much more powerful shortcut:
var myCodeMirror = CodeMirror.fromTextArea(myTextArea);
This will, among other things, ensure that the textarea's value is updated with the editor's contents when the form (if it is part of a form) is submitted.
That means you have a bug in the code which you didn't show above. Maybe you're using a weird way to submit the form, so CodeMirror can't notice and update the value?
One option would be to remove CodeMirror in the JavaScript which submits the form.

Knockout JS: Working with old validation code that changes the DOM

See edit at the bottom.
My company has a huge code base and we want to start using knockout more effectively. However, we have validation code in place already that takes care of all aspects of client-side validation. It uses jQuery to show validation error messages and to sanitize user input.
For example, if I add the class "validate-range" to an input, it will use jQuery change/focusout events to track changes and then if a value is out of the range, it will replace it with the min/max value using $(input).val(). Since this validation code makes changes this way programmatically, my knockout view model won't be updated when these kind of changes are made.
This validation code is used everywhere in the system, and can't be replaced at the moment, so in order to use knockout, I have to make it work along side this code. What i've tried so far is creating a custom value binding that adds an additional change event handler which is used to update the view model whenever the validation code changes an input's value.
This works surprisingly well in all cases except inside a foreach binding (which is the same as using the template/with binding I would imagine). My change event handler isn't being fired on any inputs inside the foreach that use the custom value binding, even though the custom binding is being reapplied to all inputs inside the foreach every time the observable array changes.
I was hoping someone has dealt with this problem before, having to make knockout work with existing javascript code that changes DOM values, and thus doesn't update the view model. Any help is greatly appreciated.
Javascript code for custom binding, creating view model, and old validation code:
// custom value binding for amounts
ko.bindingHandlers.amountValue = {
init: function (element, valueAccessor) {
var underlyingObservable = valueAccessor(),
interceptor = ko.computed({
read: function () {
var value = underlyingObservable();
return formatAmount(value);
},
write: function (newValue) {
var current = underlyingObservable(),
valueToWrite = parseAmount(newValue);
if (valueToWrite !== current)
underlyingObservable(valueToWrite);
else if (newValue !== current.toString())
underlyingObservable.valueHasMutated();
}
});
// i apply a change event handler when applying the bindings which calls the write function of the interceptor.
// the intention is to have the change handler be called anytime the old validation code changes an input box's value via
// $(input).val("new value"); In the case of the foreach binding, whenever the observable array changes, and the table rows
// are re-rendered, this code does get ran when re-applying the bindings, however the change handler doesn't get called when values are changed.
ko.applyBindingsToNode(element, { value: interceptor, event: { change: function () { interceptor($(element).val()); } } });
}
};
// view model creation
// auto create ko view model from json sent from server
$(function () {
viewModel = ko.mapping.fromJS(jsonModel);
ko.applyBindings(viewModel);
});
// old validation code
$(document).on("focusout", ".validate-range", function () {
var $element = $(this),
val = $element.val(),
min = $element.attr("data-val-range-min"),
max = $element.attr("data-val-range-max");
if (val < min)
// my change handler from custom binding doesn't fire after this to update view model
$element.val(min);
if (val > max)
// my change handler from custom binding doesn't fire after this to update view model
$element.val(max);
// more code to show error message
});
HTML code that uses the custom binding inside of a foreach binding:
<table>
<thead>
<tr>
<td>Payment Amount</td>
</tr>
</thead>
<tbody data-bind="foreach: Payments">
<tr>
<td><input type="text" class="validate-range" data-val-range-min="0" data-val-range-max="9999999" data-bind="amountValue: Amount" /></td>
</tr>
</tbody>
</table>
So in the above example, if I enter "-155" in an amount text box, my custom binding runs and sets the view model Amount to -155. Then the old validation runs and re-sets the value of the textbox to "0" with $(input).val(0). My view model doesn't get updated at this point, and still reflects the -155 value. My change event handler from the custom binding is supposed to be ran to update the view model to 0, but it doesn't.
Edit:
As pointed out in the answer, .val() does not trigger any change events. The change event handler I added didn't do anything. The reason the view model was being updated when the validation code changed a value outside of the foreach binding was because we had logic somewhere else in our javascript code that was manually triggering the change event using the blur event, which in turn triggered my custom binding to run and update the view model. This blur event handler was directly bound to the text boxes, instead of being delegated, so it worked for text boxes that were there when the page is first rendered, but not for the ones dynamically inserted by the foreach binding.
For now, I just changed this logic to delegate the events within the document, so it would include dynamically inserted text boxes, and it seems to be working fine. I'm hoping to come up with a better solution in the future.
Calling $(element).val("some value"); does not trigger the change event.
You would need to do: $(element).val("some value").change();

Categories