I need to send route params with the URL when the user clicks on submit button.
Here is my simple form
<form action="#/chat/{{username}}">
<input type="text" placeholder="enter a username..." ng-model="username" required autofocus><br/>
<input type="submit" value="submit">
</form>
But this doesn't work as the 'username' variable doesn't bind and it goes to /chat/%7B%7Busername%7D%7D instead (somebody enlighten me on why this happens)
Currently, the workaround I am following is using a hyperlink instead of a submit button
<div>
<input type="text" class="form-control" placeholder="enter a username..." ng-model="username" required autofocus><br/>
<a href="#/chat/{{username}}" class="btn btn-lg btn-primary btn-block" >Start Chatting</a>
</div>
But the problem with the above approach is that it doesn't work when the user presses ENTER key (as it is not the submit button)
So what is the correct way to achieve this?
Markup:
<form ng-submit="onSubmit()">
<input type="text" placeholder="enter a username..." ng-model="username" required autofocus><br/>
<button type="submit">submit</submit>
</form>
JavaScript Controller:
app.controller('ctrl', function($location) {
$scope.username = '';
$scope.onSubmit = function() {
$location.url('/chat/' + $scope.username);
};
});
Or something like that :)
HTML:
<form ng-submit="onSubmit()">
<input type="text" placeholder="enter a username..." ng-model="username" required autofocus><br/>
<button type="submit">submit</submit>
</form>
Controller:
app.controller('ctrl', function($state) {
$scope.username = 'example name';
$scope.onSubmit = function() {
$state.go('/chat/' + $scope.username);
};
});
Docs:
Angular Ui
$state.go('$scope.username') - will go to the state according to user name
$state.go('^') - will go to a parent state
$state.go('^.sibling') - will go to a sibling state
$state.go('.child.grandchild') - will go to grandchild state
Per another post on stack:
the $location service is on the angular.js framework out of the box and allow you to manage location object (similar in pure javascript). The $state service is part of ui-router module and allow you to manage routes in an advanced mode, throughout a state machine management of views.
If you use ui-router, you should prefer to use $state service to manages states/routes because state abstracts the concept of route and you could change the phisical routes without changing states.
Stack Post
Related
I need to publish an Input to a Form, while the Input sits outside the form. I managed to add the input, but the result is not what I excactly need (see the console output)
So I basically adding the outer input element to the form via form.$addControl(outerInput)
const MyApp = angular.module('app', []);
MyApp.controller('formCtrl', ['$scope', '$element', function($scope, $element){
$scope.dataModel = {
name: 'robert arschfick',
email: 'blabla',
age: 25,
text: 'text'
};
$scope.addOuterInputToForm = function(form, inputID){
// annoying as hell, I am retrieving the input element;
var input = angular.element(document.getElementById(inputID))[0];
form.$addControl(input);
console.log(form);
};
}]);
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app="app" ng-controller="formCtrl">
<form ng-submit="" name="testForm">
<input type="name" ng-model="dataModel.name" name="name" required>
<input type="email" ng-model="dataModel.email" name="email" required>
<input type="number" ng-model="dataModel.age">
</form>
<!-- I need to add this input the same way the inner inputs name
and email are published to the form, so that it is addressable
via its name in the form and that it is part of the form.controls
-->
<input type="text" required id="inputToAdd" name="text"
ng-model="dataModel.text">
<button ng-click="addOuterInputToForm(testForm, 'inputToAdd')">
Add Control
</button>
</div>
The input is added as a control, but the object looks different and has not all the ng $validators on it. Also I need to add it by name as a property to the form like "email" and "name" are:
This is the outside input added to the form. It misses all the ng-form attributes see the image after
This is the inside email input added to the form somehow internally. It has all the ng form properties like $untouched, $prestine etc.
So what I need is now to somehow fake this internal adding of the outer input programmatically so that the outer input is contained the same way by the form as the inner inputs "email" and "name"
Sorry for my english skills and I hope I was clear enough. Thanks in advance :)
The $addControl method needs the ngModelController of the <input>, not the <input> element itself.
To get the ngModelController of the element, enclose it in a div that has an ng-form directive:
<div ng-form="other">
<input type="text" required id="inputToAdd" name="text"
ng-model="dataModel.text">
</div>
<button ng-click="testForm.$addControl(other.text)">
Add Control
</button>
The DEMO
const MyApp = angular.module('app', []);
MyApp.controller('formCtrl', ['$scope', '$element', function($scope, $element){
$scope.dataModel = {
name: 'robert arschfick',
email: 'blabla',
age: 25,
text: 'text'
};
}]);
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app="app" ng-controller="formCtrl">
<form ng-submit="" name="testForm">
<input type="name" ng-model="dataModel.name" name="name" required>
<input type="email" ng-model="dataModel.email" name="email" required>
<input type="number" ng-model="dataModel.age">
</form>
<!-- I need to add this input the same way the inner inputs name
and email are published to the form, so that it is addressable
via its name in the form and that it is part of the form.controls
-->
<div ng-form="other">
<input type="text" required id="inputToAdd" name="text"
ng-model="dataModel.text">
</div>
<button ng-click="testForm.$addControl(other.text)">
Add Control
</button>
</div>
I'm new to Angular. I have designed a single-page app with a series of screens with input forms, some of which need to "drill down" into another screen and auto-fill the destination input form.
Screen #1: After user fills in the form he gets results in a table. Each row in the table displays an entry with the first cell containing a link the user can click for further details about it, for instance:
<td><a ng-click="drillExtDet(e.extractRequestId)"> {{e.extractRequestId}}</a></td>
The controller for this screen has a drillExtDet function as follows, which sets the id into the scope and then activates the detail screen:
$scope.drillExtDet = function(extractRequestId) {
$scope.extrReqId = extractRequestId;
$location.path('/queryExtDet');
}
The new screen is activated, but there are two issues. The form is not getting filled in, and then I also want the form to automatically submit so the details are retrieved.
Screen #2: Has an input form with a field for the extract request id and a Query button:
<form class="navbar-form navbar-center">
<div class="form-group">
<p>Extract Request ID* </p>
<input type="number" min="1" step="1" class="form-control" ng-model="extrReqId" ng-change="resetMessage()" style="width:100px">
<button type="submit" class="form-control btn btn-primary"
ng-click="queryExtDet()" style="width:100px">
<i class="fa fa-shield"> </i>Query
</button>
</div>
</form>
Below this form is a table which displays all the details. How can I get the input field populated, and how can I then make the form auto-submit?
EDITED to add Solution, thanks to accepted answer below:
The Screen #1 drillExtDet function was modified to add the extractRequestId to the $location.path:
$scope.drillExtDet = function(extractRequestId) {
$scope.extrReqId = extractRequestId;
$location.path('/queryExtDet/' + extractRequestId);
}
I added a second entry for Screen #2 in my route provider table:
app.config(function($routeProvider) {
$routeProvider
.when('/queryExtDet', {
templateUrl : 'app/queryExtDet.htm',
controller : 'queryExtDetCtrl'
})
.when('/queryExtDet/:extrReqId', { // with route param to support drill-down
templateUrl : 'app/queryExtDet.htm',
controller : 'queryExtDetCtrl'
})
In the Screen #2 controller I added the $routeParams argument:
app.controller('queryExtDetCtrl', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams) {
Then my Screen 2 controller was modified to include code to check $routeParams and invoke the queryExtDet() function which sends the request to the server and populates the new screen (the same thing that my submit function does):
$scope.extrReqId = $routeParams.extrReqId;
if ($scope.extrReqId !== undefined) {
queryExtDet($scope.extrReqId);
}
$scope.submit = function() {
//console.log("queryExtDetCtrl.submit() invoked with extrReqId="+$scope.extrReqId);
if (!$scope.extrReqId) {
$scope.message = "'Extract Request ID' is required!";
} else {
queryExtDet($scope.extrReqId);
}
}
function queryExtDet(extractRequestId) {
$scope.extrReqId = extractRequestId;
if (!$scope.extrReqId) {
$scope.message = "'Extract Request ID' is required!";
} else {
// $http.get etc.
}
}
On the input form side, the input field had to be changed from type="number" to type="text", otherwise it would not work:
<form class="navbar-form navbar-center">
<div class="form-group">
<p>Extract Request ID* </p>
<input type="text" class="form-control" ng-model="extrReqId" placeholder="Extract Request Id" ng-change="resetMessage()" style="width:100px" required>
<button type="submit" class="form-control btn btn-primary"
ng-click="submit()" style="width:100px">
<i class="fa fa-shield"> </i>Query
</button>
<i class="fa fa fa-retweet"></i> Export
</div>
</form>
By passing the extrReqId as params, you can access the previous data using API to get those details and by using ng-change and form validation, you can auto submit the data.
i expected the forms are editable and extra fields are present in new screen , if they aren't then no need to use ng-change , after getting details from api u can redirect to submit function where u can check all the details are present or not .
$scope.submit=function(){
if ($scope.userForm.$invalid) {
alert($scope.userForm.$invalid);
}else{}}
<form name="userForm" novalidate>
<table><thead> <tr><th>Name</th> <th>Country</th></tr> </thead>
<tbody>
<tr data-ng-repeat="n in names | orderBy: 'Country'">
<td> <input type="text" ng-model="n.name" name="uName" required="">
<div ng-show="userForm.$submitted && userForm.uName.$error.required">
</td>
<td>{{n.country}}</td>
</tr>
</tbody>
</table>
</form>
This seems like a really simple question but, for whatever reason my submit() method is not being invoked in JS.
HTML:
<ion-view title="Register" hide-nav-bar="true" nav-transition="none" id="page9">
<ion-content padding="true" class="manual-ios-statusbar-padding" scroll="false">
<form id="register-form4" ng-submit="register()" class="list">
<ion-list id="register-list4">
<label class="item item-input" id="register-input7">
<input type="text" ng-model="registration.email" placeholder="Email" required>
</label>
<label class="item item-input" id="register-input9">
<input type="password" ng-model="registration.password" placeholder="Password" required>
</label>
</ion-list>
</form>
<a id="register-button7" ng-click="document.getElementById('register-form4').submit();" class="button button-positive button-block">Create Account</a>
<a ui-sref="login" id="register-button8" class="button button-positive button-block button-clear">Back</a>
<div ng-show="isError">{{ loginError }}</div>
</ion-content>
</ion-view>
Controller:
.controller('registerCtrl', ['$scope', '$stateParams', "$firebaseAuth", "$location",
function ($scope, $stateParams, $firebaseAuth, $location) {
$scope.register = function() {
var email = $scope.registration.email,
password = $scope.registration.password,
confirmPassword = $scope.registration.confirmPassword;
console.log("Being submitted");
}
}])
I cannot change the <a> tag even though it would be easier just to have a form submit input but the HTML is auto-generated by Ionic Creator and I can't mess it up.
EDIT: The reason I want to submit the form in this way and not just trigger register() on click of the button is that I want to trigger the HTML required's in the form so that checks the fields have been entered so I don't have to do it manually
EDIT 2: I have changed the <a> tag to a submit button. However, this is still not invoking the register() method which suggests the form is not being submitted:
<input type="submit" value="Create Account" id="register-button7" class="button button-positive button-block">
Looking at these docs, it should work as it's pretty much the same format
I have read that 1 user things that the standard HTML submit and ng-submit do not work together. Anyone know if this is true?
You can use html input of type submit or a button inside your form. Here is a working demo at JSFiddle: https://jsfiddle.net/ydbhb5dL/
Controller:
angular
.module('App', [])
.controller('ExampleController', function ($scope) {
$scope.registration = {};
$scope.register = function () {
var email = $scope.registration.email,
password = $scope.registration.password;
console.log('Email:', email);
console.log('Password:', password);
console.log('Being submitted!');
};
});
Html:
<div ng-app="App" ng-controller="ExampleController">
<ion-view title="Register" hide-nav-bar="true" nav-transition="none" id="page9">
<ion-content padding="true" class="manual-ios-statusbar-padding" scroll="false">
<form id="register-form4" ng-submit="register()" class="list">
<ion-list id="register-list4">
<label class="item item-input" id="register-input7">
<input type="text" ng-model="registration.email" placeholder="Email" required>
</label>
<label class="item item-input" id="register-input9">
<input type="password" ng-model="registration.password" placeholder="Password" required>
</label>
</ion-list>
<input type="submit" class="button-like-link" value="Create Account (button)">
</form>
</ion-content>
</ion-view>
</div>
To solve your problem change the <a> element that submits the form to
<a id="register-button7" ng-click="register()" class="button button-positive button-block">Create Account</a>
The reason ngClick wasn't working before is because it was looking at $scope for document, which is not defined. You could add the following line to your controller, but it's not necessary.
$scope.document = document;
If you insist on not changing the form structure, you can create a new directive for your submit "button" similar to the one below (untested).
angular.module('moduleName').directive('submitForm', function() {
return {
restrict: 'A',
scope: {
formId: '='
},
link: function($scope, $elem) {
$elem.on('click', function() {
document.getElementById($scope.formId).submit();
});
}
};
});
Which you would then use as follows:
<a id="register-button7" submit-form form-id="register-form4" class="button button-positive button-block">Create Account</a>
If you still don't want to change the <a> tag to use the new directive, your only other option is defining $scope.document = document.
Or, as #J Orbe mentioned, you could use onclick instead of relying on an Angular directive (i.e. ngClick and submitForm). I'm not sure this qualifies as the "Angular way" TM, though, and you may want to avoid mixing Angular and regular JavaScript attributes as it can result in confusion. Typically, if you're using Angular, you should try to solve things using Angular.
I'm trying to use Angular's built-in form functions, specifically setPristine() to clear the form on user submit. My controller has access to $scope.newForm (my form) with all of its methods, but running $scope.newForm.$setPristine() isn't resetting the form fields.
Here is my HTML:
<div ng-controller="NewFormController">
<h3>New Entry</h3>
<form name="newForm" method="post" novalidate>
<div class="input-group">
<label>Name</label>
<input name="name" type="text" ng-model="place.name"/>
</div>
<div class="input-group">
<label>Description</label>
<textarea name="description" type="text" ng-model="place.description"></textarea>
</div>
<div class="input-group">
<label>Neighborhood</label>
<input name="neighborhood" type="text" ng-model="place.neighborhood"/>
</div>
<div class="input-group">
<label>Address</label>
<input name="location" type="text" ng-model="place.address"/>
</div>
<input type="submit" value="Submit" ng-click="submit(place)"/>
</form>
</div>
And here is the controller where I call setPristine():
app.controller('NewFormController', function($scope, $compile) {
$scope.place = {
name: 'ExamplePlace',
description: 'This is a description!',
neighborhood: 'Manhattan',
address: '112 Street Place'
};
$scope.submit = function(place) {
$scope.newForm.$setPristine();
$scope.newForm.$setUntouched();
};
});
Here is a working codepen that reproduces my problem.
Note: I'm using Angular version 1.4.3.
$setPristine only marks the form as being $pristine, which is useful for validation-driven expressions and CSS (e.g. .ng-dirty)
So, $setPristine does not clear the form's controls. In fact, it wouldn't even know how to do that. Consider, that to "clear" could mean different things to different models. "Clear" could mean "", or undefined, or null, or anything at all that a custom input control that works with ngModel could mean.
So, to properly clear the form is to modify the View Model that drives the form to whatever definition of "clear" it needs. In most cases - yours included - it is just a matter of setting the View Model to a new object:
$scope.submit = function(place) {
$scope.newForm.$setPristine();
$scope.newForm.$setUntouched();
// clear the form
$scope.place = {};
};
I have a form that I wanted be nested, but it is not possible since HTML can't accept nested form. Is there a way I can manually invoke the submit(triggers the validation, e.g. required) on first form on AngularJS?
Here's how the code looks like:
<div ng-conroller="ContactController">
<form ng-submit="saveHeaderAndDetail()">
<label for="Description">Description</label>
<input type="text" ng-model="Description" required/>
<input type="text" style="visibility:hidden" />
</form>
<form ng-submit="addToDetail()">
...
</form>
<input type="button"
ng-click="what code could trigger the first form's submit?"/>
</div>
Btw, both forms are under one controller if that helps
Try creating a directive that catches an event:
var app = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.triggerSubmit = function() {
$scope.$broadcast('myEvent');
console.log('broad');
};
$scope.onSubmitted = function() {
alert('submitted!');
};
}
app.directive('submitOn', function() {
return {
link: function(scope, elm, attrs) {
scope.$on(attrs.submitOn, function() {
//We can't trigger submit immediately, or we get $digest already in progress error :-[ (because ng-submit does an $apply of its own)
setTimeout(function() {
elm.trigger('submit');
});
});
}
};
});
<link href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css" rel="stylesheet"/>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="http://code.angularjs.org/1.0.0/angular-1.0.0.js"></script>
<div ng-controller="MyCtrl">
<form submit-on="myEvent" ng-submit="onSubmitted()">
Form...
</form>
<hr />
<a class="btn" ng-click="triggerSubmit()">Submit</a>
</div>
Original source:
http://jsfiddle.net/unWF3/
I've answered a similar question here AngularJS - How to trigger submit in a nested form
Basically, you can trigger validation by firing $validate event
isFormValid = function($scope, ngForm) {
$scope.$broadcast('$validate');
if(! ngForm.$invalid) {
return true;
}
For working code example & a small utility method which is helpful in showing validation messages, see answer in the above link.
You can have nested forms with ng-form directive. It will be like:
<form name="accountForm">
<div data-ng-form="detailsForm">
<input required name="name" data-ng-model="name">
</div>
<div data-ng-form="contactsForm">
<input required name="address" data-ng-model="address">
</div>
<button type="submit">Save</button>
</form>
That way when submit will be triggered for the accountForm it will validate nested ng-forms also.
There's an easier way to do that, You can give a name for each form that you have in your app, then you'll be able to send the entire angular object of the form that you want to trigger or do whatever you want with it. Example:
<div ng-conroller="ContactController">
<form name="myFirstForm" ng-submit="saveHeaderAndDetail()">
<label for="Description">Description</label>
<input type="text" ng-model="Description" required/>
<input type="text" style="visibility:hidden" />
</form>
<form name="mySecondForm" ng-submit="addToDetail()">
...
</form>
<input type="button"
ng-click="saveHeaderAndDetail(myFirstForm)"/>
</div>
Then in your function
saveHeaderAndDetail (myFirstForm) {
myFirstForm.$submitted = true
...
}
We can always submit a form directly using the submit
() function from javascript.
document.getElementById("myform").submit()
In this way, we can validate the form using angularjs first and if the form is valid then submit it using the submit method.