AngularJS run function after scope is loaded - angularjs

I have one form, that should be submitted with everage POST, without ajax. Just after it's rendering.
As it is an exclusion, I decided to use some jquery inside controller.
So my form:
<form name="Form" id="externalForm" action="{{form.url}}" method="POST" ng-controller="ExternalFormCtrl">
<input type="hidden" name="{{k}}" value="{{v}}" ng-repeat="(k, v) in form.form">
</form>
Amd my controller
app.controller('ExternalFormCtrl', ["$scope", "DataTransfer", function ($scope, DataTransfer) {
$scope.form = DataTransfer.get();
$('#externalForm').submit();
}]);
In DataTransfer I receive form with fields I need to send to external resource.
When it will render template, I want immidiatelly submit form with jquery.
How to submit form after rendering my form?
How to solve this task more ellegant, with angular way?
UPD: DataTransfer factory
app.factory('DataTransfer', [function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
}]);

You could use vanilla javascript
document.getElementById('externalForm').submit();

Related

AngularJS - How to pass data from View (HTML) to Controller (JS)

I am really new to AngularJS. I want to pass some object from View (HTML) to my controller (JS).
Actually my Client will send me data in HTML and I have to take that data and process that data in my controller and then display the processed output on screen. He will be using some back-end technology called ServiceNow - https://www.servicenow.com/ .
All the solutions I saw had some event like click event or change event, but in my case this has to be done on page load.
I m using Input type hidden for passing the data to the controller, seems like it's not working.
So is there any other way I can do this ?
Here's the code I am trying to use
<div ng-controller="progressController" >
<input type="hidden" value="ABCD" ng-model="testingmodel.testing">
</div>
app.controller('progressController', function($scope) {
console.log($scope.testingmodel.testing);
});
It says undefined when I console.log my variable in Controller.
You're doing console.log(...) too early. At this time your controller doesn't have any information from the view.
The second problem is that you're binding the view to a variable in controller and not the other way around. Your $scope.testingmodel.testing is undefined and it will obviously the value in the view to undefined.
Solution
Use ng-init to initialize the model and the controller's hook $postLink to get the value after everything has been initialized.
Like this
<div ng-controller="progressController" >
<input type="hidden" ng-model="testingmodel.testing" ng-init="testingmodel.testing = 'ABCD'">
</div>
app.controller('progressController', function($scope) {
var $ctrl = this;
$ctrl.$postLink = function() {
console.log($scope.testingmodel.testing);
};
});
Edit: extra tip
I don't recomment using $scope for storing data since it makes the migration to newer angular more difficult.
Use controller instead.
Something like this:
<div ng-controller="progressController as $ctrl" >
<input type="hidden" ng-model="$ctrl.testingmodel.testing" ng-init="$ctrl.testingmodel.testing = 'ABCD'">
</div>
app.controller('progressController', function() {
var $ctrl = this;
$ctrl.$postLink = function() {
console.log($ctrl.testingmodel.testing);
};
});
You should use the ng-change or $watch
<div ng-controller="progressController" >
<input type="hidden" value="ABCD" ng-model="testingmodel.testing" ng-change="change()">
</div>
app.controller('progressController', function($scope) {
$scope.change = function(){
console.log($scope.testingmodel.testing);
}
});
Or:
app.controller('progressController', function($scope) {
$scope.$watch('testingmodel.testing', function(newValue, olValue){
console.log(newValue);
}
});
If you use ng-change, the function is only called if the user changes the value in UI.
If you use $watch anyway, the function is called.
You can't use value attribute for set or get value of any control, angularJS use ngModel for set or get values.
Here You should try like this way
app.controller('progressController', function($scope) {
//from here you can set value of your input
$scope.setValue = function(){
$scope.testingmodel = {}
$scope.testingmodel.testing = 'ABCD';
}
//From here you can get you value
$scope.getValue = function(){
console.log($scope.testingmodel.testing);
}
});
if you want to bind from html side then you should try like below
<input type="text" ng-model="testingmodel.testing">
<input type="hidden" ng-model="testingmodel.testing">

How to access DOM from AngularJS controller?

I am trying to submit a form from controller function in AngularJS. I need to do this without using jQuery because the target site
gives me a cross domain error when I use jQuery. I need to just post the form. Is it possible to do from controller without using jQuery?
I tried to use $element service but it seems to be jquery way of doing it and it is not really going to the target url.
Thank you for any suggestions.
<form name="myForm" id="myForm" method="post" action="#Model.Settings["URL"]" ng-controller="FormCtrl as fctrl">
</form>
setControllers.controller('FormCtrl', ['$scope', '$state', '$element', 'DataService',
function ($scope, $state, $element, service) {
var fctrl = this;
function init() {
$element.find('#myForm').submit();
};
init();
}]);
Well, you can totally do
function init() {
document.getElementById("myForm").submit();
};
but neither my solution, nor your approach are very angular-ish. You should probably go for some sort of directive.
Well. The angular way of submitting a form is by using ng-submit. Here's an example of how you can achieve it, in its simplest form, pun intended:
html
<html ng-app="FormModule">
<section ng-controller="formController as form">
<form ng-submit="form.submit()">
<label>Name</label>
<input ng-model="form.data.name" placeholder="Insert your name" />
<button type="submit">Submit My Name To The Server</button>
</form>
</section>
</html>
javascript
angular
.module('FormModule', [])
.controller('formController', formCtrl);
formCtrl.$inject = ['$scope']; // or whatever injection
function formCtrl($scope) {
var form = this;
form.data = {}; // ng-model form.data.name will be available in this
form.submit = submitTheForm;
function submitTheForm() {
$.post('url', form.data); // or whatever HTTP service you're using
}
}
Anyway, to help you understand and write better Angular code, here's how I learned writing better, and it is reflected in the code above
John Papa Angular 1.x Styleguide
ngSubmit Documentation

angularjs -how to clear the form data from a clear button outside sitting outside the form

I have a form with a submit button which works fine. However I need to clear the form data from a clear button which is sitting outside the form on top right of the page. The clear button exist in a parent controller and sits above the form in top right header. The form sent from the clear button always comes up as undefined, which is because the clear button is not part of the form.
How do I pass the same instance of the form to clear? How do I clear the data? If this is a design issue I still need a workaround.
Here is a fiddle I have created to mimic that. Any help will be appreciated.
https://jsfiddle.net/SobDan/vj67rtb2/
<div ng-app>
<div class="col-md-10">
<h2>Todo</h2></div>
<div class="col-md-2">
<button class="btn pull-right" ng-click="clear(TodoForm)"> Close</button>
</div>
<br>
<div ng-controller="TodoCtrl">
<form name="TodoForm" ng-submit="addTodo()" name="testForm">
<input type="text" ng-model="todoText" size="30" placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
function MainCtrl($scope) {
$scope.clear = function(form) {
alert(form); // the form is undefined
if (form.$dirty)
form.setPristine(); // clean this form
else
alert("form not dirty");
};
};
function TodoCtrl($scope) {
$scope.todoText = "test";
$scope.addTodo = function() {
alert("Submitted");
$scope.todoText = "";
// submit logic works fine
};
}
You should use $broadcast to communicate between controllers rather than trying to access the form which is outside scope.
Here is the fiddle and the explanation below
$broadcast function is used to broadcast events to all child $scope. Any interested child $scope can register to listen for the event using $on function. This functionality is used to communicate between controllers.
In your case, we signal to clear the form by broadcasting an event called clearForm from $rootScope. The TodoCtrl $scope listening on the event clearForm will receive a signal to clear form fields.
app.controller("MainCtrl", function($scope, $rootScope) {
$scope.clear = function(form) {
$rootScope.$broadcast("clearForm");
};
});
app.controller("TodoCtrl", function($scope) {
$scope.$on("clearForm", function() {
if ($scope.testForm.$dirty) {
$scope.testForm.$setPristine();
$scope.todoText = "";
} else {
alert("form not dirty");
}
});
});
AngularJS 1.1.x +
$scope.form.$setPristine() is only available from AngularJS version 1.1.x.
$setPristine() will only set the form status to pristine and will not clear the form field. You need to manually clear it by nullifying the $scope variables which will be reflected on the screen.
if ($scope.testForm.$dirty) {
$scope.testForm.$setPristine();
$scope.todoText = "";
}
AngularJS 1.0.x +
$setPristine function is not available in 1.0.x version.
The example Fiddle in your question seem to be configured to 1.0.x
In 1.0.x you simply clear the $scope variables
$scope.$on("clearForm", function() {
$scope.todoText = "";
});

syncing variable across pages using angularJs

I have a html page with a link as follows:
<div ng-if="!adminCtrl.valid">
<div><a target="_blank" ng-href="https://api.instagram.com/oauth/authorize/?client_id=xxx&redirect_uri=http://localhost:8888/igSuccess.html&response_type=token">Authorize to Instagram</a><br/></div>
</div>
This goes to redirect page on success where the code is
<div ng-controller="AdminController">
<h2>You can close this tab/window</h2>
</div>
The control is same for both pages as follows:
app.controller('AdminController', ['$scope','$routeParams','$location', function($scope,$routeParams,$location){
var actrl = this;
actrl.valid = false;
var token = $location.absUrl();
if(token.indexOf('access_token') > -1){
console.log('found token so will do special');
actrl.valid = true;
$scope.$apply();
}
}}
I am expecting the link to disappear once the new page opens as i am updating the valid variable value.
i know the flaw seems to be the cross page communication. so how to deal with it?
Controllers are 'flushed' when you change views. To keep data from a view/controller to another, store your data within a Service.
UPDATE
controller:
app.controller('AdminController', [
'$scope', '$routeParams', '$location', 'ExampleService', function ($scope, $routeParams, $location, ExampleService) {
var actrl = this;
// Watches the service's value for changes and applies it to the controller
$scope.$watch(function(){return ExampleService.valid}, function(newValidValue){
actrl.valid = ExampleService.valid;
});
var token = $location.absUrl();
if (token.indexOf('access_token') > -1) {
console.log('found token so will do special');
ExampleService.valid = true;
// No need for this
// $scope.$apply();
}
}
}
Service:
app.service('ExampleService', [
function () {
//All properties here are kept through-out your app's life time
this.valid = false; // Init to false
}
}
To share data between Controllers in Angular JS, use a named Service to encapsulate the data. In your case, I would typically define an Auth service that provides a few methods for getting and setting the access_token for a user:
module.factory('Auth', function(){
return {
isValid: function(){ /* Check that a User is authenticated... */ },
setToken: function(token){ /* Store the token somewhere... */ },
getToken: function(){ /* Fetch the token from somewhere... */ }
};
});
To share data across "pages" -- tabs or windows in your browser -- even in a Single Page Application (SPA) like this, store the data in cookies or localStorage. You can use angular-local-storage by grevory (GitHub) to abstract the details of using localStorage with a cookie fall-back in non-compatible browsers.
The reason that one page cannot see the valid value defined in the other is because each page gets a separate instance of AdminController, each of which get their own separate instance of $scope tied to their respective DOM elements. Setting valid on the $scope of the redirect landing page has not effect on the completely detached $scope instance in the originating page.
You'd encounter similar difficulties with a trivial same-page example (CodePen):
angular.module('scope-example', [])
.controller('ExampleCtrl', function($scope) {
$scope.value = 'Initial Value';
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form class="pure-form" ng-app="scope-example">
<fieldset ng-controller="ExampleCtrl">
First instance of <code>ExampleCtrl</code>:
<br>
<input ng-model="value">
<label>{{value}}</label>
</fieldset>
<fieldset ng-controller="ExampleCtrl">
Second instance of <code>ExampleCtrl</code>:
<br>
<input ng-model="value">
<label>{{value}}</label>
</fieldset>
<fieldset ng-controller="ExampleCtrl">
Third instance of <code>ExampleCtrl</code>:
<br>
<input ng-model="value">
<label>{{value}}</label>
</fieldset>
</form>
Even though each of the <fieldset> elements have identical ng-controller directives associated, each gets its own instance of ExampleCtrl and $scope, so the value property isn't shared between them. This holds true for any directive.

Retrieve all inputs values from a form AngularJS

I have a massive form with more or less 80 / 90 inputs.
My main problem is How can I pass all those inputs belonging to unique form in an ajax request without map the inputs manually into a object?
I know that with jquery you can use serialize() function selecting the form. Is there any helper function in angular to achieve that?
Thanks
Indeed, as Michal's comment suggested, it doesn't look like you are using ng-model.
Angular's jqLite doesn't support serialize() since with Angular one would typically build a ViewModel that would then be bound to a form.
But, if you are out of luck, you could add jQuery.js to get the serialize() support and create a simple directive - serializer - that would act on a form.
app.directive("serializer", function(){
return {
restrict: "A",
scope: {
onSubmit: "&serializer"
},
link: function(scope, element){
// assuming for brevity that directive is defined on <form>
var form = element;
form.submit(function(event){
event.preventDefault();
var serializedData = form.serialize();
scope.onSubmit({data: serializedData});
});
}
};
});
And use it as follows:
<form serializer="submit(data)">
<input name="foo">
<input name="bar">
<button type="submit">save</button>
</form>
And in the controller:
$scope.submit = function(data){
console.log(data);
}
plunker
EDIT:
If you are using ng-model and in fact have a proper ViewModel, then this is the "Angular way" and so, you should have some object that is bound to the form inputs - you should just submit that.
<form name="foo" ng-submit="onSubmit()">
<input ng-model="fooObject.a">
<input ng-model="fooObject.b">
...
</form>
$scope.fooObject = {};
$scope.onSubmit = function(){
$http.post("url/to/server", {data: $scope.fooObject})
.success(...);
}

Resources