I am building an AngularJS application that includes modal windows which contain forms and are loaded into the DOM asynchronously (when the appropriate button is clicked). The forms work fine, but I cannot properly check if they are valid. Here's an example:
HTML
<div ng-app="myapp" ng-controller="MyCtrl">
<form novalidate name="myform" ng-submit="submitForm(myform)">
<input type="text" required ng-model="myname" />
</form>
</div>
JavaScript
var app = angular.module('myapp', []);
app.controller("MyCtrl", function($scope) {
$scope.submitForm(form) {
if(form.$valid) {
// Do http stuff here
}
};
});
If this form is loaded asynchronously, the form variable has value NaN and form.$valid is undefined. However, if I load it with the rest of the page, it works fine. Does anyone know how to force AngularJS to populate the scope variable for the form? Thanks!
When you include a form using ng-include a childScope is created. The parent and the childScope cant access eachothers scopes. Therefore the .$valid comes up empty.
I had a similiar issue the other day and got a working solution that suited me in this thread:
AngularJS $setValidity on childScope form
Related
I have a main JS file which holds a bunch of functions which are used throughout my app. In this JS file I set the routing of the app.
main.js (MainController):
$stateProvider
.state('page1', {
url : '/',
templateUrl : 'page1.html',
controller : "Page1Controller"
})
.state('page2', {
url : '/',
templateUrl : 'page2.html',
controller : "Page2Controller"
});`
In Page 2 I have a form
<div class="outer" ng-controller="MainController">
<div class="page" ng-init="test();">
<form id="page2_form" name="page2_form">
<input type="text" id="field1" name="field1"/>
<input type="text" id="field2" name="field2"/>
</form>
</div>
</div>
I will be using the scope to check the form for validation but currently it is undefined. I am checking this by using the $scope.$watch.
page2.js (Page2Controller):
$scope.$watch('page2_form', function(page2_form) {
console.log(page2_form);
});
But it is printing out "undefined". I assume that the routing is actually loading in the controller as the ng-init works. However, It does work if I try adding ng-controller="Page2Controller" to <div class="page"> this outputs the form on the $scope.$watch which is what I want but it is running it twice since the controller is being loaded twice.
Why is it not outputting the form even though the controller is being loaded in by the routing?
UPDATE
My fix:
Adding $scope.form = {}; to page2.js (Page2Controller) and changing the form to this:
<form id="form.page2_form" name="form.page2_form"></form>
This means that I can now access fields in the form with
$scope.form.page2_form[fieldname]
However, I'm not sure why I have to do this now as I have past applications where I did not need to do the form.form_name aspect of it.
I think your problem is related to JavaScript ProtoTypal inheritance and how Angular.js handling that in 'ng-*' directives.
Kindly check that link for more deep understanding to that topic.
https://github.com/angular/angular.js/wiki/Understanding-Scopes
For my webpage I use Django 1.9 for the server-side and AngularJs for some client-side tasks (validation etc).
Also for the CSS I use Bootstrap (and the Angular-Ui).
Now I created the forms I need in Django which inserts them on the actual page. Amongst others, I have an input field of type file which lets the user upload a file.
When the user has chosen a file, I would like to do some checks in AngularJs. The problem is: I have no clue how I can get some kind of callback from Django to know that the upload-file window was closed.
My current solution involves a plain javascript function which is bound to the upload field and calls an AngularJs function, but this does not work properly.
So in my forms.py it looks like that:
class UploadForm(forms.Form):
fa_file = forms.FileField(label='Select a Fasta file',
widget=forms.TextInput(attrs={'type': 'file'})
The part of the html page where this field is inserted looks like that:
<div class="panel-body">
<input type="text" id="uploadFile" placeholder="Choose File" disabled="disabled"/>
<div class="file-upload btn btn-sm btn-primary">
<span>Upload</span>
{{ form.fa_file }}
</div>
</div>
The javascript function which is bound to the file-upload field is:
<script>
document.getElementById("id_fa_file").onchange = function () {
document.getElementById("uploadFile").value = this.value;
angular.element(this).scope().changeFaFileValue(this.value);
};
</script>
This on change method is executed whenever the user finishes choosing a file. Essentially this is the behavior I want to achieve and the AngularJS function of my controller 'changeFaFileValue' is executed as well.
But it seems that the execution happens in its own scope. I can tell because I have a watcher in my AngularJS controller for a variable which is changed in 'changeFaFileValue' and this watcher is not triggered when the function is called via this plain Javascript on change function.
But if I call the 'changeFaFileValue' from somewhere in my controller, the watcher executes as expected.
The methods in the controller look like this:
$scope.$watch('allow_submit', function(){
console.log("IT WORKED.");
});
$scope.changeFaFileValue = function(newPath){
$scope.fa_file_js = newPath;
$scope.allow_submit = !$scope.allow_submit;
}
I think I am missing something important here.
Can you please tell me what would be the correct way to achieve the desired behavior? Is my approach correct at all?
Hello I am running an app wich needs a lot of form validation across pages, so I am trying to get validation patterns from a service i am using amongst the controllers.
The problem here is the ng-pattern isn't reacting the right way when I enter a correct email address.
This is a plunker and here's the code for the form
<form method="POST" action="#" name="newsletterForm" id="newsletterForm" ng-controller="newsletterForm" novalidate>
<input ng-pattern="/{{patterns.email}}/" type="email" name="email" ng-model="email" required />
<button type="submit">Invia</button>
{{newsletterForm.email.$error.pattern}}
</form>
This is the app.js code
var app = angular.module('plunker', []);
app.controller('MainCtrl', function(){});
app.service('validationPatterns', function() {
this.getPatterns = function() {
return {
email: "^([a-zA-Z0-9\'\.\-\_]{2,64})([\#]{1})([a-zA-Z0-9\.\-\_]{2,64})([\.]{1})([a-zA-Z]{2,16})$"
}
}
});
app.controller('newsletterForm', function($scope, validationPatterns){
$scope.patterns = validationPatterns.getPatterns();
});
I assume the problem might be that when angular renders the pattern inside the input tag it renders it escaping the backslashes
^([a-zA-Z0-9'.-_]{2,64})([#]{1})([a-zA-Z0-9.-_]{2,64})([.]{1})([a-zA-Z]{2,16})$
I have already tried adding the double backslashes in the service to make angular render it correctly but it's still not working.
Any ideas?
ng-pattern works with a $scope variable. In your case it should be
<input ng-pattern="patterns.email"
Updated plunker
I am using nested ng-includes in my app . Outer one is login screen for different application and inner ng-include includes 2 templates . My login screen is designed in two steps . First email will be checked then the password .
I am having issue in form post . In second template password one when the form is posted , suppose if password not matched then it shows error but my ng-include template is reset to first one . I am not using ng-submit instead action attribute is define which post the form .
Here is my code
Second ng-include
<div ng-include="currTemplate" class="slide"></div>
$scope array contains templates
$scope.templates = ['/Content/app/templates/AddAccount.html', '/Content/app/templates/Login.html'];
When controller loads it is set to 0
$scope.currTemplate = $scope.templates[0];
I have a form in Login template
<form name="form" method="post" action="{{model.loginUrl}}">
in which action attribute is define . When this form posted and results in error my template is changed to AddAccount.html and error is shown. I can't use ng-submit to post form need help ?
Looks like you are doing a full page reload with the post. This will reset all your client side values to their defaults. You need to submit the form as an XHR (ala ng-submit) or return data from the failure that let's you adjust the correct template to show.
I'm trying to redirect from my Angular app to a non-angular page. If I have a redirect function on the $scope and invoke it directly from a UI element via ng-click it works as expected. If I call the function from within another $scope function, though, the page reloads or remains as is. I suspect there is a scoping issue here, but I can't tell what it is. I also tried $window.location.assign() and got the same result.
Why is the redirect working one way, but not the other? Thanks!
Link to CodePen
JS
angular.module('myApp',[]);
angular.module('myApp').controller('myCtrl', [ '$scope', '$window', function($scope, $window){
$scope.destination = "http://www.clientsfromhell.net";
$scope.redirectStarted = false;
$scope.redirect = function(target){
$window.location.href = target;
$scope.redirectStarted = true;
};
$scope.wrapperFunction = function() {
var altDestination = "http://www.reddit.com/r/CrappyDesign";
$scope.redirect(altDestination);
};
}]);
HTML
<div data-ng-app="myApp" data-ng-controller="myCtrl">
<ul>
<li>Invoke redirect() directly: <input type="button" value="Direct Invocation" data-ng-click="redirect(destination)" /></li>
<li>Invoke from wrapper function: <input type="button" value="From Wrapper" data-ng-click="wrapperFunction()" /></li>
</ul>
<div data-ng-show="redirectStarted">
Redirect started
</div>
</div>
UPDATE
dfsq was right that my problem was not related to Angular. My app is a .NET application, and there was a form on the master page. Because I was using a button of type=submit, the form was being submitted, which cancels the redirect unless you do a preventDefault() on it. In my debugging, I was using an ng-click function on a header element to do the redirect. That worked fine because it didn't submit the form, but it also led me down the wrong path in thinking it was a scoping problem.
This has nothing to do with Angular. The reason why the wrapper redirect is not working, is that it is using different redirect URL (on reddit domain). This resource has restricted content policy preventing it from being displayed in iframe on different domain pages.
Сorresponding error:
Refused to display 'http://www.reddit.com/r/CrappyDesign' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.
The first destination URL doesn't have this limitation, so it works flawlessly.
From documentation about X-Frame-Options:
The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a , or . Sites can use this to avoid clickjacking attacks, by ensuring that their content is not embedded into other sites.