Binding a custom JavaScript control to AngularJS - javascript

I have a set of pure JavaScript controls that are initiated like this:
var myControl = new SVGColorPicker("name", "#rrggbb");
myControl.insert("tagIdValue");
or, alternatively, in html:
<div><script>myControl.draw()</script></div>
The controls have getValue() and setValue(value) methods, and they harbor a hidden html input element so that the values appear in the form submits.
I am looking for some guidance how to bind these controls to the AngularJS famework. Obviously, I'd create a custom directive for every type. But how to tie in the control value reading and updating so that the two-way binding works flawlessly, and I could also make use of the special AngularJS form functionality (states, validation, etc)

Related

HTML5 / JavaScript / JQuery - Best way to get form associated with input

Before HTML5, I used to be able to easily find the form associated with an input using jQuery, because all inputs were contained within the form element.
For example, with jQuery I would do something like:
jQuery('.info-container input').closest('form')
I still would like to use jQuery because I use some features that are easier to implement in jQuery. But, with HTML5, inputs can be outside of the form element. For example the following can be anywhere in the HTML but still part of the form:
<input name='city' form='address_form'>
Is there any easy way in jQuery to get the form associated with a given input/button/select ?
You can get the form property to get the associated form.
$($('input[name=city]').prop('form'))
I believe this will work whether the input is inside a form or uses the form attribute to connect with a form.
How about just get list using this.
var inputs = $(document).find('input[form="address_form"]');
then you can find what input you want within form "address_form" using their name. But if you just need one element, just like this
var inputs = $(document).find('input[form="address_form"][name="city"]');

Set the value of a form element using javascript - still prompts required field

I am setting values on a form in an iframe via Javascript.
Please note that I do not have access to the page displayed in the iframe. My Javascript page is on the same server, so it has access to the form displayed.
//HTML of Forename field in form control
<input class="form-control" id="Forename" type="text" data-bind="value: dto.Forename">
Javascript setting the value:
var frameNode = document.getElementById('frm1');
var fieldNode = frameNode.contentDocument.getElementById('Forename');
fieldNode.value = FirstName; //previously defined
The values set successfully (see attached img). However, when I hit SAVE, I still get a 'values Required' message. I suspect this is because the Knockout Javascript libraries that binds the value with the view model, needs a keypress.
Even when I manually go into the form and press Enter/Tab after each value, I still get the message. It's only when I change the Forename and Surname manually to something else that the Save is successful.
Has anybody done something like this before? Thanks
In this image you can see the values are set
I believe the problem you're experiencing is actually due to a deeper issue involved in using a knockout binding. Updating the value of a UI control directly has no effect because the real underlying value is stored in a javascript view-model object. The DOM element only mirrors that value, and updates are performed using a change event hook under the hood. When you change the value manually on the UI the change event is triggered and the view-model value gets updated.
Knockout.js Docs
So to properly update the values you should try using the knockout library to update the underlying data:
var frameNode = document.getElementById('frm1');
var fieldNode = frameNode.contentDocument.getElementById('Forename');
var viewModel = ko.dataFor(fieldNode);
viewModel.dto.Forename(FirstName); //value setting works like a function
If you can't get that to work you can also try manually triggering the change event. That's far easier if you have jQuery, but can still be done without. See How can I trigger an onchange event manually?

How to get the value to view models when a control's value is changed using jQuery?

I declare a textbox, dropdown list in knockout js. If I dynamically change the value of the textbox or dropdown using jQuery like this...
$('#IdNo').val(_IDNo);//for textbox
$('#IdNo').change();
$('#Subjects option').filter(function () { return $.trim($(this).val()) == parseInt(subjectbind); }).attr('selected', true);//for dropdown
$('#Subjects').change();
...then change() does not bind the value to the knockout. The changed value does appear in the UI but is not reflected in the View Model for further actions.
If you want to make sure Knockout takes note when you manually update the DOM, you need to use the trigger method like so:
$('#Subjects').trigger('change');
The change method can be used to register handlers for the event.
PS. If you're manually updating the DOM, then you should evaluate why / how you're using KnockoutJS...

Is it possible to chain an event handler programatically in a directive?

I've been trying to figure out a way to trigger the validation routines on an input element when a button is clicked in the same form. I've been looking at a few different ways of doing this. What seems to be the least convoluted is to create a directive that modifies an input button to fire the $validate method on the target form element. I've set this up without too much trouble but I've gotten blocked at how to modify the ngClick event handler so that it triggers the $validate while leaving the original HTML-defined ngClick intact.
I was attempting to use the directive template function to extract the original ngClick method and chain it to the new ngClick function defined in the directive. This started to turn into a mess quite quickly and I'm concerned about how brittle it might be.
Is there a way to intercept the ngClick handler in a directive and to still have the original functionality intact?
Alternately, I'm open to suggestions about how to fire the validation routines on the input field when the button is clicked with minimal involvement of the controller layer.
This is a classical example of an XY-question (if not a double-XY-question).
You don't need to "chain event handlers" (whatever you mean by that). Neither do you need to, I think, trigger the validation manually just because you are validating against external data.
Validation in Angular just runs - and it is not meant to be triggered other than by changing the data.
To add your own custom validator you need to create a directive (which it seems like you did). In that directive you probably need to specify what you are validating against, like an array of strings against which you want to check for duplicates.
Let's say, for simplicity, that you want to validate against another value in the ViewModel. Suppose, this how it would be used:
<input ng-model="bar">
<form name="form1">
<input ng-model="foo" not-equal-to="bar">
</form>
<span ng-show="form1.$error.notEqualTo">error: foo is equal to bar</span>
So, you need to create a directive notEqualTo that adds a validator to the ngModel.$validators pipeline. This directive also needs to $watch for changes to bar and re-set the validity:
app.directive("notEqualTo", function(){
return {
require: "ngModel",
scope: {
notEqualTo: "="
},
link: function(scope, element, attrs, ngModel){
// register "notEqualTo" validator
ngModel.$validators.notEqualTo = function(modelValue){
return validate(modelValue, scope.notEqualTo);
};
// rerun validation on changes to scope.notEqualTo
scope.$watch("notEqualTo", function(){
ngModel.$setValidity("notEqualTo",
validate(ngModel.$modelValue, scope.notEqualTo));
});
function validate(one, other){
return one !== other;
}
}
};
});
plunker

AngularJS multiple forms - how to submit forms by name?

I'm using Angular UI Bootstrap accordion with a form in each Accordion. How can I submit the form by the id or name of the form? In essence I have an click event bound to the accordion and I would like to pass the name of the form as a parameter somehow and then submit it?
thanks
http://plnkr.co/edit/GMJ8fTWqSw2STnG4V2Ri?p=preview
Instead of passing in the form's name or id, you should pass in the object that the form is bound to, or just dynamically pull it from the controller's $scope.
In angular it is considered bad form to have anything DOM related in your controller. By using the DOM in a controller it dramatically reduces the test-ability of the controller which is one of the key pillars that angular is built upon.
example:
<form ng-submit="handleSubmit(formData)">
<input ng-model="formData.field1"/>
<input ng-model="formData.field2"/>
</form>
Based upon your plnkr example to call the function defined in your form's rcSubmit attribute do this:
formElement.bind('submit', function () {
$parse(attributes.rcSubmit)();
});
The documentation for $parse states Converts Angular expression into a function which is exactly what you need in this case.

Categories

Resources