Programmatically submit a form from an Angular directive - javascript

In my Angular 1.5.X app I have a directive with the following template
<form id="pdfDownloadForm"
name='pdfDownloadForm'
method="POST"
action="{{ downloadUrl }}">
<input type="hidden" name="data" value="" />
<button type="button" ng-click="submit()">Submit</button>
</form>
When the form is submitted, I would like to do the following
Set the value of the hidden parameter data to a value retrieved from a remote service
Submit the form
Attempted Solution
Presumably the easiest way to set the hidden parameter is with
<input type="hidden" name="data" ng-model="dataValue" />
and then before submitting the form, assign to scope.dataValue the value retrieved from the remote service?
I tried to submit the form programmatically with
scope.submit = function () {
$('#pdfDownloadForm').submit();
}
But this causes the following error:
Error: [$rootScope:inprog] $apply already in progress

Since you're using Angular 1.5+, there's no reason to use scope - either use controllerAs syntax or, preferably, components.
I'd implement your task by interrupting first submit call and populating hidden field instead. Any subsequent submits are allowed to happen.
// inside contorller
onSubmit(event) {
if (!this.dataValue) {
event.preventDefault();
this.initializeData();
}
}
initializeData() {
$http.get('/my-data-source').then((response) => {
this.dataValue = response.data.value;
this.pdfDownloadForm.submit(); // requires <form name="$ctrl.pdfDownloadForm">
});
}
See https://docs.angularjs.org/api/ng/directive/ngSubmit
It's better to avoid using ngClick here since form can be submitted by Enter instead of button click.

<button type="button" ng-click="submit">Submit</button>
should be
<button type="button" ng-click="submit()">Submit</button>
so after your edit to your post, this wasn't the solution? have your tried it?

Related

Javascript Function only works in Console [duplicate]

I have a form in Angular that has two buttons tags in it. One button submits the form on ng-click. The other button is purely for navigation using ng-click. However, when this second button is clicked, AngularJS is causing a page refresh which triggers a 404. I’ve dropped a breakpoint in the function and it is triggering my function. If I do any of the following, it stops:
If I remove the ng-click, the button doesn’t cause a page refresh.
If I comment out the code in the function, it doesn’t cause a page refresh.
If I change the button tag to an anchor tag (<a>) with href="", then it doesn’t cause a refresh.
The latter seems like the simplest workaround, but why is AngularJS even running any code after my function that causes the page to reload? Seems like a bug.
Here is the form:
<form class="form-horizontal" name="myProfile" ng-switch-when="profile">
<fieldset>
<div class="control-group">
<label class="control-label" for="passwordButton">Password</label>
<div class="controls">
<button id="passwordButton" class="secondaryButton" ng-click="showChangePassword()">Change</button>
</div>
</div>
<div class="buttonBar">
<button id="saveProfileButton" class="primaryButton" ng-click="saveUser()">Save</button>
</div>
</fieldset>
</form>
Here is the controller method:
$scope.showChangePassword = function() {
$scope.selectedLink = "changePassword";
};
If you have a look at the W3C specification, it would seem like the obvious thing to try is to mark your button elements with type='button' when you don't want them to submit.
The thing to note in particular is where it says
A button element with no type attribute specified represents the same thing as a button element with its type attribute set to "submit"
You can try to prevent default handler:
html:
<button ng-click="saveUser($event)">
js:
$scope.saveUser = function (event) {
event.preventDefault();
// your code
}
You should declare the attribute ng-submit={expression} in your <form> tag.
From the ngSubmit docs
http://docs.angularjs.org/api/ng.directive:ngSubmit
Enables binding angular expressions to onsubmit events.
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page).
I use directive to prevent default behaviour:
module.directive('preventDefault', function() {
return function(scope, element, attrs) {
angular.element(element).bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
}
});
And then, in html:
<button class="secondaryButton" prevent-default>Secondary action</button>
This directive can also be used with <a> and all other tags
You can keep <button type="submit">, but must remove the attribute action="" of <form>.
I wonder why nobody proposed the possibly simplest solution:
don't use a <form>
A <whatever ng-form> does IMHO a better job and without an HTML form, there's nothing to be submitted by the browser itself. Which is exactly the right behavior when using angular.
Add action to your form.
<form action="#">
This answer may not be directly related to the question. It's just for the case when you submit the form using scripts.
According to ng-submit code
var handleFormSubmission = function(event) {
scope.$apply(function() {
controller.$commitViewValue();
controller.$setSubmitted();
});
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
It adds submit event listener on the form.
But submit event handler wouldn't be called when submit is initiated by calling form.submit(). In this case, ng-submit will not prevent the default action, you have to call preventDefault yourself in ng-submit handler;
To provide a reasonably definitive answer, the HTML Form Submission Algorithm item 5 states that a form only dispatches a submit event if it was not submitted by calling the submit method (which means it only dispatches a submit event if submitted by a button or other implicit method, e.g. pressing enter while focus is on an input type text element).
See Form submitted using submit() from a link cannot be caught by onsubmit handler
I also had the same problem, but gladelly I fixed this by changing the type like from type="submit" to type="button" and it worked.
First Button submits the form and second does not
<body>
<form ng-app="myApp" ng-controller="myCtrl" ng-submit="Sub()">
<div>
S:<input type="text" ng-model="v"><br>
<br>
<button>Submit</button>
//Dont Submit
<button type='button' ng-click="Dont()">Dont Submit</button>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Sub=function()
{
alert('Inside Submit');
}
$scope.Dont=function()
{
$scope.v=0;
}
});
</script>
</body>
Just add the FormsModule in the imports array of app.module.ts file,
and add import { FormsModule } from '#angular/forms'; at the top of this file...this will work.

How to change array value in javascript through functions? [duplicate]

I have a form in Angular that has two buttons tags in it. One button submits the form on ng-click. The other button is purely for navigation using ng-click. However, when this second button is clicked, AngularJS is causing a page refresh which triggers a 404. I’ve dropped a breakpoint in the function and it is triggering my function. If I do any of the following, it stops:
If I remove the ng-click, the button doesn’t cause a page refresh.
If I comment out the code in the function, it doesn’t cause a page refresh.
If I change the button tag to an anchor tag (<a>) with href="", then it doesn’t cause a refresh.
The latter seems like the simplest workaround, but why is AngularJS even running any code after my function that causes the page to reload? Seems like a bug.
Here is the form:
<form class="form-horizontal" name="myProfile" ng-switch-when="profile">
<fieldset>
<div class="control-group">
<label class="control-label" for="passwordButton">Password</label>
<div class="controls">
<button id="passwordButton" class="secondaryButton" ng-click="showChangePassword()">Change</button>
</div>
</div>
<div class="buttonBar">
<button id="saveProfileButton" class="primaryButton" ng-click="saveUser()">Save</button>
</div>
</fieldset>
</form>
Here is the controller method:
$scope.showChangePassword = function() {
$scope.selectedLink = "changePassword";
};
If you have a look at the W3C specification, it would seem like the obvious thing to try is to mark your button elements with type='button' when you don't want them to submit.
The thing to note in particular is where it says
A button element with no type attribute specified represents the same thing as a button element with its type attribute set to "submit"
You can try to prevent default handler:
html:
<button ng-click="saveUser($event)">
js:
$scope.saveUser = function (event) {
event.preventDefault();
// your code
}
You should declare the attribute ng-submit={expression} in your <form> tag.
From the ngSubmit docs
http://docs.angularjs.org/api/ng.directive:ngSubmit
Enables binding angular expressions to onsubmit events.
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page).
I use directive to prevent default behaviour:
module.directive('preventDefault', function() {
return function(scope, element, attrs) {
angular.element(element).bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
}
});
And then, in html:
<button class="secondaryButton" prevent-default>Secondary action</button>
This directive can also be used with <a> and all other tags
You can keep <button type="submit">, but must remove the attribute action="" of <form>.
I wonder why nobody proposed the possibly simplest solution:
don't use a <form>
A <whatever ng-form> does IMHO a better job and without an HTML form, there's nothing to be submitted by the browser itself. Which is exactly the right behavior when using angular.
Add action to your form.
<form action="#">
This answer may not be directly related to the question. It's just for the case when you submit the form using scripts.
According to ng-submit code
var handleFormSubmission = function(event) {
scope.$apply(function() {
controller.$commitViewValue();
controller.$setSubmitted();
});
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
It adds submit event listener on the form.
But submit event handler wouldn't be called when submit is initiated by calling form.submit(). In this case, ng-submit will not prevent the default action, you have to call preventDefault yourself in ng-submit handler;
To provide a reasonably definitive answer, the HTML Form Submission Algorithm item 5 states that a form only dispatches a submit event if it was not submitted by calling the submit method (which means it only dispatches a submit event if submitted by a button or other implicit method, e.g. pressing enter while focus is on an input type text element).
See Form submitted using submit() from a link cannot be caught by onsubmit handler
I also had the same problem, but gladelly I fixed this by changing the type like from type="submit" to type="button" and it worked.
First Button submits the form and second does not
<body>
<form ng-app="myApp" ng-controller="myCtrl" ng-submit="Sub()">
<div>
S:<input type="text" ng-model="v"><br>
<br>
<button>Submit</button>
//Dont Submit
<button type='button' ng-click="Dont()">Dont Submit</button>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Sub=function()
{
alert('Inside Submit');
}
$scope.Dont=function()
{
$scope.v=0;
}
});
</script>
</body>
Just add the FormsModule in the imports array of app.module.ts file,
and add import { FormsModule } from '#angular/forms'; at the top of this file...this will work.

Not sure why I can't get javascript to display answer to a calculation [duplicate]

I have a form in Angular that has two buttons tags in it. One button submits the form on ng-click. The other button is purely for navigation using ng-click. However, when this second button is clicked, AngularJS is causing a page refresh which triggers a 404. I’ve dropped a breakpoint in the function and it is triggering my function. If I do any of the following, it stops:
If I remove the ng-click, the button doesn’t cause a page refresh.
If I comment out the code in the function, it doesn’t cause a page refresh.
If I change the button tag to an anchor tag (<a>) with href="", then it doesn’t cause a refresh.
The latter seems like the simplest workaround, but why is AngularJS even running any code after my function that causes the page to reload? Seems like a bug.
Here is the form:
<form class="form-horizontal" name="myProfile" ng-switch-when="profile">
<fieldset>
<div class="control-group">
<label class="control-label" for="passwordButton">Password</label>
<div class="controls">
<button id="passwordButton" class="secondaryButton" ng-click="showChangePassword()">Change</button>
</div>
</div>
<div class="buttonBar">
<button id="saveProfileButton" class="primaryButton" ng-click="saveUser()">Save</button>
</div>
</fieldset>
</form>
Here is the controller method:
$scope.showChangePassword = function() {
$scope.selectedLink = "changePassword";
};
If you have a look at the W3C specification, it would seem like the obvious thing to try is to mark your button elements with type='button' when you don't want them to submit.
The thing to note in particular is where it says
A button element with no type attribute specified represents the same thing as a button element with its type attribute set to "submit"
You can try to prevent default handler:
html:
<button ng-click="saveUser($event)">
js:
$scope.saveUser = function (event) {
event.preventDefault();
// your code
}
You should declare the attribute ng-submit={expression} in your <form> tag.
From the ngSubmit docs
http://docs.angularjs.org/api/ng.directive:ngSubmit
Enables binding angular expressions to onsubmit events.
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page).
I use directive to prevent default behaviour:
module.directive('preventDefault', function() {
return function(scope, element, attrs) {
angular.element(element).bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
}
});
And then, in html:
<button class="secondaryButton" prevent-default>Secondary action</button>
This directive can also be used with <a> and all other tags
You can keep <button type="submit">, but must remove the attribute action="" of <form>.
I wonder why nobody proposed the possibly simplest solution:
don't use a <form>
A <whatever ng-form> does IMHO a better job and without an HTML form, there's nothing to be submitted by the browser itself. Which is exactly the right behavior when using angular.
Add action to your form.
<form action="#">
This answer may not be directly related to the question. It's just for the case when you submit the form using scripts.
According to ng-submit code
var handleFormSubmission = function(event) {
scope.$apply(function() {
controller.$commitViewValue();
controller.$setSubmitted();
});
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
It adds submit event listener on the form.
But submit event handler wouldn't be called when submit is initiated by calling form.submit(). In this case, ng-submit will not prevent the default action, you have to call preventDefault yourself in ng-submit handler;
To provide a reasonably definitive answer, the HTML Form Submission Algorithm item 5 states that a form only dispatches a submit event if it was not submitted by calling the submit method (which means it only dispatches a submit event if submitted by a button or other implicit method, e.g. pressing enter while focus is on an input type text element).
See Form submitted using submit() from a link cannot be caught by onsubmit handler
I also had the same problem, but gladelly I fixed this by changing the type like from type="submit" to type="button" and it worked.
First Button submits the form and second does not
<body>
<form ng-app="myApp" ng-controller="myCtrl" ng-submit="Sub()">
<div>
S:<input type="text" ng-model="v"><br>
<br>
<button>Submit</button>
//Dont Submit
<button type='button' ng-click="Dont()">Dont Submit</button>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Sub=function()
{
alert('Inside Submit');
}
$scope.Dont=function()
{
$scope.v=0;
}
});
</script>
</body>
Just add the FormsModule in the imports array of app.module.ts file,
and add import { FormsModule } from '#angular/forms'; at the top of this file...this will work.

AngularJs - submit the form programmatically

I read several answers on this topic but they don't seem to apply to my problem. My problem is quite complex. I have a form which uses ReportViewer.ASPX. The form is defined as following:
<form name="form" novalidate role="form"
sm-dirty-check
id="reportViewer"
method="post"
action="~/Infrastructure/ReportViewer/reportViewer.aspx"
target="viewerIFrame"
ng-show="crud.showForm" class="ng-cloak">
#* Form inputs *#
<input type="hidden" name="labelType" value="Rental" />
<input type="hidden" name="labelLayoutId" value="{{ crud.model.lbLayoutId }}" />
<input type="hidden" name="itemsToPrint" value="{{ crud.jsItemsToPrint }}" />
The actual forms are defined in the tabs using ng-form (I only shared the top portion of my Edit form which is relevant to my question).
I also have these buttons at the bottom of the form:
<button type="submit"
ng-if="crud.model.lbLayoutId!==0"
name="generateLabelButton"
id="generateLabelButton"
class="btn btn-primary pull-left"
ng-click="crud.generateLabel()"
ng-disabled="crud.isSaveButtonDisabled">
#Labels.generateLabel
</button>
<div class="pull-left generateLabelButton">
<data-desc:type ng-if="crud.model.lbLayoutId===0"
value="#Labels.generateLabel"
keep-pristine="true"
on-after-selection="crud.layoutSelected(selectedValue)"
title="{{ '#string.Format(Labels.selectX, Labels.labelLayout)'}}"
param="layouts"
message="#string.Format(Labels.selectX, Labels.labelLayout)"
selected="crud.model.lbLayoutId"
descrip-value="descrip"
id="layoutPickerButton"
name="layoutPickerButton"
button-type="button"
type="7"
filter-by="Label"
description="crud.model.lbLayout">
</data-desc:type>
</div>
So, if I have lblLayoutId defined, I have my regular submit button and I press it and get my form submitted and all is well.
If I don't have the lblLayoutId defined (it's 0), I need to use a directive which has a template for a button, when I press it, it opens a modal form to pick the layout, etc.
So, my problem is that after I picked the layout, I need to submit my form so the label can appear.
I tried making the directive to be of type submit (button-type property), this didn't work.
I also tried the following code in the method which is executed by the button when value is selected:
rentalEquipmentsCrudController.prototype.layoutSelected = function (selectedValue) {
this.model.lbLayoutId = selectedValue;
$("#generateLabelButton").click();
}
rentalEquipmentsCrudController.prototype.generateLabel = function () {
if (this.model.lbLayoutId === 0) return;
this.jsItemsToPrint = "";
this.itemsToPrint = this.getItemsToPrint();
this.jsItemsToPrint = JSON.stringify(this.itemsToPrint);
angular.element($("#viewerIFrame").contents()
.find("#reportViewer_ReportViewer")).empty();
let actionPath = angular.element($("#reportViewer")).attr("action");
if (actionPath.slice(-3) !== "pdf") actionPath += "/Labels.pdf";
angular.element($("#reportViewer")).attr("action", actionPath);
this.showViewer = true;
};
The layoutSelected method is executed from my directive and the next code is executed by my regular button.
So, I'm at lost as how to make it work.
The role of forms in client-side AngularJS applications is different than in classical roundtrip apps, it is desirable for the browser not to translate the form submission into a full page reload. Instead post JSON data and receive JSON data responses. Go to the server for data, but not html/js/css etc.
Read AngularJS <form> Directive API Reference - Submitting a form and preventing the default action.
You don't want to combine ng-click with a button of type="submit", this will still cause the form to submit (non-programmatically). Instead, use type="button". Alternatively, you can keep type="submit" but add the ng-submit="crud.generateLabel()" to the form element
<form>
...
<button type="button" ng-click="crud.generateLabel()">...</button>
</form>
Alternatively:
<form ng-submit="crud.generateLabel()">
...
<button type="submit">...</button>
</form>

How to handle multiple submit buttons in a form using Angular JS?

I'm using AngularJS and I have a form where the user can enter data. At the end of the form I want to have two buttons, one to "save" which will save and go to another page, and another button labeled "save and add another" which will save the form and then reset it - allowing them to enter another entry.
How do I accomplish this in angular? I was thinking I could have two submit buttons with ng-click tags, but I'm using ng-submit on the form element. Is there any reason I NEED to be using ng-submit - I can't remember why I started using that instead of ng-click on the button.
The code looks something like:
<div ng-controller="SomeController">
<form ng-submit="save(record)">
<input type="text" name="shoppingListItem" ng-model="record.shoppingListItem">
<button type="submit">Save</button>
<button type="submit">Save and Add Another</button>
</form>
</div>
And in the controller SomeController
$scope.record = {};
$scope.save = function (record) {
$http.post('/api/save', record).
success(function(data) {
// take action based off which submit button pressed
});
}
You can keep both ng-click and type="submit". In the ng-click you can just update a parameter of your controller and validate that in the event ng-submit:
<div ng-controller="SomeController">
<form ng-submit="save(record)">
<input type="text" name="shoppingListItem" ng-model="record.shoppingListItem">
<button type="submit">Save</button>
<button type="submit" ng-click="SaveAndAddClick=true">Save and Add Another</button>
</form>
So this approach avoids you from adding a method and then calling a redundant code.
Thanks
ngSubmit allows you to press Enter while typing on the textbox to submit. If that behavior isn't important, just use 2 ngClick. If it is important, you can modify the second button to use ngClick. So your code becomes:
<div ng-controller="SomeController">
<form ng-submit="save(record)">
<input type="text" name="shoppingListItem" ng-model="record.shoppingListItem">
<button type="submit">Save</button>
<button ng-click="saveAndAdd(record)">Save and Add Another</button>
</form>
</div>
Make them all buttons and type=submit. It makes it a little cleaner not mixing and matching inputs and buttons. So basically you're trying to execute one method in your controller to handle either button click.
<div ng-controller="SomeController as sc">
<form ng-submit="sc.execute(record)">
<input type="text" name="shoppingListItem" ng-model="record.shoppingListItem">
<button type="submit" ng-model="sc.saveButtonVal" ng-click="sc.saveButtonVal=true>Save</button>
<button type="submit" ng-model="sc.saveAndAddButtonVal" ng-click="sc.saveAndAddButtonVal=true">Save and Add Another</button>
</form>
</div>
So, in your js file you'll have something like this.
function SomeController() {
var sc = this;
sc.execute = function(record) {
//initialize the vars
sc.saveButtonVal = false;
sc.saveAndAddButtonVal = false;
sc.resetButtonValues = function() {
sc.saveButtonVal = false;
sc.saveAndAddButtonVal = false;
};
if (sc.saveButtonVale) {
//do save only operation
} else if (sc.saveAndAddButtonVal) {
//do save and add op
}
// reset your button vals
sc.resetButtonValues();
}
}
As I see it, you have two options:
1: Use an ngClick event on the "save and add another" button and remove the "type='submit'" portion. Then in whatever function you call gor the ngClick, you can save and then reset the values, calling save() within that function.
2: Remove the ngSubmit altogether and just use ngClicks for both buttons.
If someone looking for a simple approach then just create a flag and toggle between button and submit.
<button type="{{isButton == true ? 'button' : 'submit'}}" >Save</button>
<button type="{{!isButton == true ? 'button' : 'submit'}}" >Update</button>
Need to handle the flag according to user action.
ng-submit has other advantages too. For example, invalid form will not be submitted. It is always better to use ng-submit instead of ng-click. However, in your scenario, better approach would be
use ng-click on buttons.
validate form in controller. Keep in mind that ng-click will submit the form even if it is not valid.
call two different $scope.functions on two different ng-click in the somecontroller.
Hope it helps.
Remove ng-submit from "form" element and define ng-click functions separately on each button with type 'submit'.For invalidation check, define name property in form element tag. And check validation in scope function.
<div ng-controller="SomeController">
<form name="saveForm">
<input type="text" name="shoppingListItem" ng-model="record.shoppingListItem">
<button type="submit" ng-click="save(record)">Save</button>
<button type="submit" ng-click="saveOther(record)">Save and Add Another</button>
</form>
Scope Function:
$scope.record = {};
$scope.save = function (record) {
if(this.saveForm.$valid)
{
$http.post('/api/save', record).
success(function(data) {
// take action based off which submit button pressed
});
}
}

Categories

Resources