AngularJS - can't access $valid on dynamic inputs - javascript

UPDATE: I've added a custom directive which allows me to access the input with a dynamically generated name, but $valid is still undefined.
I'm very new to Angular (trying to switch from jQuery) and I find it pretty awesome, however I've been pulling my hair for hours on this and can't figure out what's causing the issue.
The workflow of the UI that I'm trying to achieve is for a user to click on a step, which then shows an input field, which he has to fill in (validation is required so I'm trying to use ng-required/ng-minlength).
If it passes the validation it should show a tick icon and activate the next step which works the same way.
Now the issue is that I can access the form element, but the object I get is a DOM object and it doesn't include the $valid property, which I need for checking whether the form/field is valid.
17:20 lines are:
console.log($scope.step1); //undefined
console.log(step1); //dom object
console.log(step1.value); //dom object
console.log(step1.value.$valid); //undefined
I've been googling a lot and many questions on SO say that I should be able to access the form through the $scope variable, but unfortunately I can't, though it is accessible via a simple variable name "step1" (dynamically generated form name). I can also access the "value" named field, but it's still just a DOM object so no $valid is available.
JSFiddle: http://jsfiddle.net/Iber/vtvnquee/
My questions are:
Am I on the right path in terms of Angular style of coding?
Is my "wizard app" code logical? I mean, maybe I should use a different approach to build those steps?
What am I doing wrong and why can't I access the $valid properties?
Really want to understand Angular because it seems like a proper framework for large apps and the way to go for me.

Form validation in angular relies on two things:
Your form (or ng-form) element must have a 'name' attribute.
<form name="myform">
Your input (or select) fields must have a 'name' attribute and an ng-model.
<input type="text" name="name" ng-model="name" />
The reason that your form and input fields need a name attribute is because that is how you will find the models on $scope and perform client side validation.
For example
$scope.myform.name.$error.required
$scope.myform.name.$valid
$scope.myform.name.$invalid
[EDIT]
I see that you've already followed these guidelines in your fiddle.
The reason that it does not work is because the name attribute cannot be an interpolated value.

Related

angularjs - set certain inputs with data to $pristine or untouched correctly

After researching i am still stuck on my predicament. I am using the latest version of foundation for apps with angular 'pre-embedded'.
I have a form which is used for both adding and editing data - lets say its for a job and it tracks employees days on the job. on load of the view the form is completely empty and contains two sections - the job details and the employees details.
first the user would have to enter and save the details in the job section (in order to create the id for the job so the employees can be linked to it) for the employees section to be activated. This works fine and is enabled by the job id being set to > 0 (-1 being default on load);
This all works fine so far, but i have a function in my controller to allow loading in an existing job record. when the user blurs on one of three fields the controller checks the data object for jobs matching these unique fields and loads (angular.copy) in the data in the scopes 'job' model. When this is loaded all form inputs are set and marked as dirty.
obviously my required behavior is that if the job details are loaded in by the system the form is not marked as dirty so as to allow me to know if the job details have been edited at any point after. the same is required of a new job that has been saved and given an id.
as i understand it the setPristine() function actually resets the form and model, similar to form[0].reset() but I may be wrong. I also suspect untouched may be a way to go?
also i should mention that the contains all sections to this view including the add employee inputs in the employee section.
I understand I can simply remove the ng-dirty class manually but have read this then does not update the angular way and will not identify further edits.
Is there a way i can functionally remove the ng-dirty from all child inputs of an element and not all in the form and without removing the loaded data too?
note: all inputs by default are linked (via ng-model) to their relevant models and data is loaded in the controller to the model.
It seems I've misunderstood pristine from the other posts, after further tests it is only the field that the unique data was entered into that is changed to dirty. I simply need to call setPristine on this after loading the existing record and then maybe loop through all elements within this section to test them. $setPristine does not clear the input as i read previously.

Text box not updating displayed value from directive

Apologies for the long post, but I am attempting to provide as much information as I can.
I have inherited a rather complex app that utilizes Angular. Because of an NDR, I cannot post code samples, and as of yet, have been unable to recreate my issue in a smaller, less complicated stand alone plnkr. I’m sure if I could, I could then figure out what I need to do to fix this issue. I know your hands are tied because I cannot post code, nor can I recreate the problem in a plnkr, but I’m going to do my best to give as much information as possible to hopefully get some general suggestions on what to look at next.
First, the code/architecture:
I have a form.html. Inside that form.html, we are using ng-repeat to iterate through a list of fields pulled from the database, and displaying each field. The fields at the form level are a custom type.
<field data=“attrs.field[fieldId]” on-update”updateField” field=“field"></field>
updateField(fieldId, data) is defined in form.directive.js, and is used to update the data back to the database when it changes. This part works reliably.
form.html also contains a button that is used to clear the contents of the field.
<button class="btn btn-sm btn-danger" tooltip="Clear Field" ng-click="updateMetadataField(field._id, null)" ng-show="field.editable">
The field uses templates to generate the proper input, based upon the type. We use selects, texts, textedits, and many other custom fields. We use predictive text in many of these fields as well.
Here is one example:
<input name={{field._id}} type="text" class="form-control" ng-model="data" ng-blur="onUpdate(field._id, data)" ng-if="field.editable" typeahead="suggestion as suggestion for suggestion in field.suggestions | filter:$viewValue | limitTo:8" />
There is a field.directive.js that has its own methods used to manipulate the custom input fields that have been written. That contains:
scope: {
data: '=',
field: '=',
onUpdate: '='
},
The problem:
When initially loading the form, if there is data in a text field, and the user hits the Clear Field button, the database gets updated and the string is removed from the text box.
When a user first types text into a field, then leave the field, ng-blur calls updateField, and the data gets written to the database. This works fine. When a user clicks on the Clear Field button for a text or textedit field, the value in the database gets set back to null, but the string displayed in the text box doesn’t get cleared. However, if we reload the form, the text field shows empty.
At first I thought this had to do with an isolated scope inside of the fields stemming from the use of ng-repeat. However, a simple output statement of the attrs.field at the top of the form.html showed that every time the text box is updated, the parent scope is updating as well. So this doesn’t appear to be the issue.
I’ve decided that perhaps the issue is that the $modelValue of the input is getting updated, but the $viewValue is not (or at the very least we need to call $render for some reason). I’ve since been attempting to inject ngModel into the form.directive.js in order to access these variables and methods to see if I’m correct, but I’m having a heck of a time doing so.
1st attempt:
I tried injecting ngModel into the form.directive.js’s directive’s argument list. When I load the form, I get the following error:
Error: [$injector:unpr] Unknown provider: ngModelProvider <- ngModel <- fieldsDirective
http://errors.angularjs.org/1.4.7/$injector/unpr?p0=ngModelProvider%20%3C-%20ngModel%20%3C-%20fieldsDirective
I’m rather new to Angular, and I found the information at the link to be rather confusing. Some help understanding what they’re talking about there would be awesome!
2nd attempt:
Injecting ngModel in as an argument to the function in the link field in form.directive.js, along with a require: ’ngModel' statement in the return {} section. When I load the form, I get the following error:
Error: [$compile:ctreq] Controller 'ngModel', required by directive ‘fields', can't be found!
http://errors.angularjs.org/1.4.7/$compile/ctreq?p0=ngModel&p1=fields
When I follow this link it says that it is looking for the required directive controller on the current DOM element or its ancestor (when using require: ‘^ngModel’). However, these are being used by templates in the field used in the form. Does this qualify as being used in the current DOM element this way?
3rd attempt:
Assuming that the template is the reason I cannot include ngModel, I found this: Updating ng-model within a directive that uses a template. I changed the data: ‘=‘ scope mapping to data: '=ngModel’. Unfortunately this hasn’t changed any behavior at all.
I’m stuck. Can anyone provide me some other avenues to explore, or perhaps shed light as to why my including ngModel is failing?
Thanks in advance!
This is definitely tricky to diagnose without being able to see what you're actually doing. I would skip the ngModel injection as dangerous over-complication. I'd guess it's actually something simple at its core.
Now, my shot in the dark: Are you actually updating the $scope.data variable you're trying to work with? It looks to me like you're passing the callback updateField from the parent, which is defined in the parent. That would mean that when you reference $scope.anyVariable in the function, it's referring to the parent's $scope element (you'd be working in the parent controller's closure, not the directive's). You could have updateField take the child scope as a parameter, have the directive pass its $scope through that, and you'd know that you're actually working with the correct $scope object.
When that actual variable that's bound to ngModel is properly modified, the display should change in turn.
So we finally solved the issue.
The Clear Field button was contained inside of the Form.html, but was acting upon the input inside of the field template inside of field.html. Great for not having to repeat code, but unfortunately this just wasn't updating the value inside of the input for us when we used the Clear Field button to set it to null.
To solve, we moved the Clear Field button inside of each template, and changed around the callbacks so that updates made to ng-model in the input go to field's directive then bubble up to form's directive as required.
This fixed (or at least worked around) our issue.
Thanks!

Force / inform angularJS that the model has updated after we update separate fields from safari extension

I'm building a Safari extension that will auto complete a bunch of fields found on an online form.
That online form is using angularJS to tie in the value in the fields with the value in a model. I don't know much about angularJS, but I could deduce that from the ng-model=user.firstname.value etc. directives found in the input tags.
My Safari extension will get the first name input field, and set firstNameField.val("A first name") in order to add a value in that field.
However, this doesn't seem to update the angularJS model, since if I am to exit that field manually, it'll color itself red, saying there is no data, even though there clearly is some text.
From my extension, I don't seem to be able to access the angular object unfortunately, so I cannot call the methods that I read need to be called (angular.$apply).
Seems like what I am trying to do is doable, since the LastPass extension correctly adds values to the input fields and causes the model to be correctly updated – the fields don't color themselves red.

Cannot access the value of the selected item of a disabled drop down, in action class (struts 2)

On a Jsp page I have some select elements which were disabled after a value was selected (Disabled them in javascript). Now when the form is submitted, I can not access those selected values in the action class.
I know for sure that this is caused by the select elements being disabled because, when I tried the same without making them disabled, it worked fine.
Now I don't understand why is this so. I thought maybe I should enable them before the form is submitted, but it does not seem a good idea.
I faced this problem while implementing this : Creating struts 2 forms dynamically on jsp using java script .
(You can find the code there. Although I don't think you will need the code, because it is clear where the problem is.)
Here I am able to access the values of text fields but I can not access the values of select elements.
I asked this question separately because I thought this is a different topic.
Thanks!!
Disabled fields by W3 specifications will not get posted on the server side so this issue is not related to the Struts2 but in generic an HTML way to go
Disabled controls
i am not sure why you want to use disabled control for your form.things can be done using readOnly attribute or use hidden fields
You can set them in hidden field through java script and pass it to action

Trying to access javascript elements inside a page

I hope someone can help me. I'm trying to access the text box inside a webpage so I can do some scripting, e.g. placing text in fields, checking a box and clicking submit, to automate my employees' workflow. It's confusing as heck because I cannot find the name/id/whatever that will allow me to manipulate the form. I can see the name of the field I'm trying to get at using Firebug ("history[comment]") and the id, if that helps ("history_comment") but no matter what I do, the form will not be manipulated. Based on the other scripting I've done, this Applescript:
do JavaScript "document.forms[1].history_comment.value='Testing';" in document 1
should do the job, telling the browser to put "Testing" in the appropriate field. I've substituted other names I think might be what it wants, and tried referencing any other forms (forms[2], forms[3]), all for naught. I'm actually confused a bit more because there are no statements in the HTML, so it could be I'm screwing up there.
I've posted an HTML dump of the form at http://images.jlist.com/testform.html (with dummy information of course) in case any kind soul can take a gander and give me some direction. My goal is to be able to put information into the Comment field. Is there a script I can run that will tell me the complete name (as far as the browser is concerned) of every element in the form?
if you can use jquery, then you can do it quite easily using the following command
$("history_comment").val("HELLO");
The JavaScript should be:
document.getElementById("history_comment").value='Testing';
document.forms is non-standard and, as is the case in your example code, fails if the element is not inside a form. This is fairly common in AJAX applications and another good reason to avoid document.forms.
What #Kikuchyo wrote, though it's actually strictly incorrect not to enclose form elements like textarea in a form tag. You'll also need that form tag if (as you suggest) you want to submit the form programmatically. Since you're already accessing that text box, you can get the form from that in your javascript function:
var thetext=document.getElementById('history_comment');
thetext.value='whatever you want to put in there';
thetext.form.submit(); // all form elements have a 'form' property
You can get at the checkbox state as document.getElementById('history_notify').checked; it's a Boolean value, so set it to true or false, and use it in conditionals directly.
Of course, if (as, looking at the form, you likely want to) you want an AJAX submit, you'll need to check out the documentation for whatever wrapper library you're using.
since your element is a text area, it should be done like this:
document.getElementById('history_comment').innerHTML = 'HELLO';
using innerHTML instead of value

Categories

Resources