Can't access form from inside AngularJS controller - angularjs

I am trying to manually reset a form from inside an AngularJS controller but I can't access it using either $scope, or using controllerAs. When I log $scope.SupportForm, it returns undefined.
HTML
<form name="supportForm" id="supportForm" novalidate>
<label for="message">Message</label>
<textarea name="message" id="message" model="$ctrl.formData.message" maxlength="5000" required></textarea>
<button type="submit" data-ng-click="$ctrl.submitForm($ctrl.formData)" data-ng-disabled="supportForm.$invalid">
Request support
</button>
</form>
Contoller
function GeneralSupportController($scope, $state, $timeout, $stateParams, SupportService, $uibModal) {
var vm = this;
vm.formData = {};
vm.submitForm = submitForm;
function submitForm(data) {
console.log('$scope.supportForm : ', $scope.supportForm)
}
}
I have also tried adding ngModel to the form, but it also doesn't work.
Question
Any idea why the form isn't being assigned to the scope?

Form is assigned to scope in your code. (https://plnkr.co/edit/7eYvApaW36DrRmvK >> it works) I guess actually you have following:
<div ng-if="...">
<form name=...
In this case form is assigned to nested scope of ng-if not controller scope. You have several solutions:
pass form to submit function $ctrl.submitForm(supportForm... useful when u have several forms
put form into controller <form name="$ctrl.supportForm" do it when u have one form

Related

Form object undefined when using Angularjs blockUI

I'm using Angularjs, version 1.5, and i have specified a form in my html as follows:
<div class="row" ng-show="showForm">
<form class="form-horizontal" name="myForm" novalidate role="form">
</form>
</div>
In the corresponding controller i have a function that resets the form and calls pristine:
$scope.myForm.$setPristine();
Until now everything works fine.
I then try to use blockUI (https://github.com/McNull/angular-block-ui)
by changing the above div to:
<div class="row" ng-show="showForm" block-ui="myBlock">
so the only addition is: block-ui="myBlock"
however, when the controller code runs i get:
TypeError: Cannot read property '$setPristine' of undefined
When debugging i see that the form object does not exist! When removing block-ui="myBlock", everything works fine again.
Any ideas?
Thanks in advance
Try something like these:
function MyCtrl($scope, $timeout, blockUI) {
$scope.form = {};
$scope.submit = function() {
var myBlockUI = blockUI.instances.get('myForm');
$scope.form.myForm.$setPristine();
myBlockUI.start();
$timeout(function() {
// Stop the block after some async operation.
myBlockUI.stop();
}, 3000);
};
}
and view:
<form name="form.myForm" novalidate ng-submit="submit()" block-ui="myForm">
<input type="text">
<button>
Submit
</button>
</form>
I have same trouble like you with undefined form on $scope, but found these trick with using additional object form on SO. Plunk here.

unable to set validity on form

I am trying to set a validation token "fooname" for a form through its controller, on the click of a button based on a condition.
However it looks like form.$error.fooname is not getting set. {{form.$error.fooname}} is parsed as null.
javascript:
angular.module('app', [])
.controller('controller', ['$scope', function ($scope) {
$scope.data={};
$scope.data.validate=function () {
if ($scope.data.name=="foo") {
$scope.form.$setValidity("fooname",true);
}
};
}]);
html:
<form name="form" ng-controller="controller"
ng-submit="data.validate()" ng-init="form.$setValidity('fooname',false)"
novalidate>
<input type="text" ng-model="data.name" name="name"/>
<button type="submit">Submit</button><br/>
{{data}}<br/>
{{form.$error.fooname}}
</form>
The $setValidity function defined on form controller, takes three parameter as per the source code:
form.$setValidity = function(validationToken, isValid, control) {
Also to fail a validation you need to set the value to false not true. Change your expression to
$scope.form.$setValidity("fooname",true,$scope.form);
Also the $error for FormController returns the list of controllers that are failing the validation, so you need to adjust you code accordingly.

$scope undefined in Angularjs

I'm creating an Angular app for learning (I'm all new to Angular) and currently stuck at this point.
Following is my Angular controller
cookingPad.controller('RecipeCreateController', function($scope, $http) {
$scope.recipeSave = function($scope, $http){
//code
};
});
Following is my form
<form id="signup-form_id" ng-submit="recipeSave()">
//some html
<input type="text" name="name" ng-model="recipeFormData.name" id="name" class="form-control input-lg no-border-radius" placeholder="Name">
// some more html
<button class="btn btn-lg btn-success" id="save1" type="submit"><i class="fa fa-save"></i> Save</button>
</form>
So when I enter something in the text box and click save it comes inside the recipeSave function. but when I check the $scope variable with chrome dev tools, it shows it as
$scope
undefined
What could be the reason? Everything else in my Angular works im on Angular 1.2.4, I found several SO questions but none of them works for me.
Don't re-declare the controller args in recipeSave:
$scope.recipeSave = function() {
Make that change and things should start working. Your template is explicitly invoking recipeSave() with no arguments, and you want to access your controller arguments via closure anyway, which will work fine.
This is due to the recipeSave method having $scope and $http as arguments. Dependency Injection works on the Controller/Service/Filter/etc level, atributes from different scopes as recipeSave won't solve dependency injection.
In other words, on the view you are not passing parameters when you execute the recipeSave function, so the function gets undefined as the value of both parameters.
Cheers

Angular JS - Change path, Same controller, don't reload scope

I know it's been asked so many times here and I found it too. But it could not solve my problem.
Here is the case. I have one AngularJS application.
I have a list page. I have a button to add. When I click on add button, a pop-up window will come with a form. I want to change the URL when the pop-up comes but in the same controller.
Also I would like to add some other buttons on each, some html display as popup-or other location, but same controller without reloading all scope when url changes.
What I have tried.
app.js
var WebClientApp = angular.module('WebClientApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ui.bootstrap',
'ngRoute'
]);
WebClientApp.config(function ($routeProvider) {
$routeProvider
.when('/groups/:template', {
templateUrl: 'groups.html',
controller: 'GroupCtrl'
}
groups.html
<div>
<button ng-click="showAdd()">Add Group</button>
<div ng-include src="views/listpage.html">
<div ng-if="addGroupModal" class="popup-modal">
<form name="addGroup" ng-submit="addandEditGroup()">
<input type="text" ng-model="group.name">
</form>
<div>
<div ng-if="editGroupModal" class="popup-modal">
<form name="editGroup" ng-submit="saveGroup()">
<input type="text" ng-model="group.name">
<input type="text" ng-model="group.desc">
<input type="text" ng-model="group.id">
</form>
<div>
Controllers.js
WebClientApp.controller('GroupCtrl', function ($scope,$http, $location, $routeParams) {
$scope.group = {};
$scope.showAdd=function(){
$location.path('/groups/add');
}
var template = $routeParams.template;
switch(template){
case 'add':
loadAddPage();
break;
case 'edit':
loadEditPage();
break;
default:
loadListPageHideAll();
break;
}
function loadAddPage() {
$scope.addGroupModal=true;
$scope.editGroupModal=false;
}
function loadEditPage(){
$scope.addGroupModal=false;
$scope.editGroupModal=true;
}
function loadListPageHideAll() {
$scope.addGroupModal=false;
$scope.editGroupModal=false;
// connect to server and list all groups
}
$scope.addandEditGroup = function() {
$location.path('/groups/edit');
}
$scope.saveGroup = function() {
// Save group with $scope.group.
$location.path('/groups');
}
});
When I click on add button, it will show the add form. When I enter group name, and submit, it should show edit form after changing url with the group name filled in the form. But when I try, the value of group object becomes empty since the url is changing. I added the following in controller, but don't know what to do exactly after.
$scope.$on('$routeChangeStart', function(event, present, last) {
console.log(event,present,last);
});
How to assign the scope variables of last route to present route scope. I tried reload on search to false also, But it didnt work.
There might be an error here :
function loadEditPage(){
$scope.addGroupModal=false;
$scope.editGroupModal=true;
}
There are probably some typos in the HTML template code you posted, but what you are basically doing is hiding the parent addGroupModal and showing the child editGroupModal. Remove the nesting and the tags like this:
<div ng-if="addGroupModal" class="popup-modal">
<form name="addGroup" ng-submit="addandEditGroup()">
<input type="text" ng-model="group.name">
</form>
</div>
<div>
<div ng-if="editGroupModal" class="popup-modal">
<form name="editGroup" ng-submit="saveGroup()">
<input type="text" ng-model="group.name">
<input type="text" ng-model="group.desc">
<input type="text" ng-model="group.id">
</form>
</div>
</div>
Here is the plunkr ( hit enter to submit the form): http://plnkr.co/edit/MGT8HZ4lpgVWCkWlt8Ak?p=preview
If this is what you want to acheive, honestly you are complicating things ... There are simpler solutions.
I see! What you want to acheive is to have a reference of the old group variable before the route was changed... And you want to do that using the same controller...
Ok, to get the group from the last controller, you are half way there . You have to store the group somewhere because the targetScopes and currentScopes you receive in the $routeChange listeners don't point to the scopes.
http://plnkr.co/edit/HfK3fhVtZ4bxHtpiFR3B?p=preview
$scope.group = $rootScope.group || {};
$scope.$on('$routeChangeStart', function(event, present, last) {
console.log('start change route');
$rootScope.group = event.currentScope.group;
console.log('target scope group ',event.currentScope.group);
});
I agree the rootScope might not be the best place to keep that variable, but you can also put it inside an angular constant of variable.

From AngularJS how to pass data from a controller+template to another controller+template?

I'm building an application with AngularJS and Slim PHP framework for the backend, now I completed my 1st form and created a route to the template for it. Now my problem arise when I want to pass my data to another controller, I need to pass the data to another controller+view(template), I don't want to pollute my first view neither the controller of it and so I really want/need to pass the data to another controller which I could play with my data and another form (the 2nd form is for calculation and other stuff)...So you can call the first controller a pre-save, while the real data save (backend to DB) will only happen in the second controller+template. Here is a short of my 1st template view that has the form:
<form novalidate id="formAdd" name="formAdd" class="form-horizontal well col-md-7 col-md-pull-5" method="post">
<fieldset>
<legend>Transaction form</legend>
<div class="form-group">
<label for="symbol" class="col-sm-4 control-label">Symbol</label>
<div class="col-sm-5 symbols">
<input type="text" name="symbol" class="form-control" ng-model="trsn.symbol" placeholder="symbol" required />
</div>
</div>
<div class="form-group">
<label for="accnt_id" class="col-sm-4 control-label">Account</label>
<div class="col-sm-5">
<select id="accnt_id" name="accnt_id" ng-model="trsn.accnt_id" class="form-control" required>
<option value="">...</option>
<option ng-repeat="account in trsn.accounts" value="{{account.accnt_id}}">{{account.accnt_name}}</option>
</select>
</div>
</div>
<!-- ....etc, etc.... -->
<div class="form-actions col-sm-8 col-sm-offset-4">
<button type="submit" name="save_btn" class="btn btn-primary" ng-disabled="formAdd.$invalid" ng-click="preSaveTrsn(trsn, formAdd)">Save transaction</button>
<button type="reset" class="btn btn-default">Cancel</button>
</div>
</fieldset>
</form>
then the app with the module and routes:
var investingApp = angular.module('investingApp', ['ngSanitize','ngResource', 'ngRoute'])
.config(function($routeProvider, $locationProvider) {
$routeProvider.when('/new-trsn',
{
templateUrl: 'templates/StockTransaction.html',
controller: 'StockTransactionController'
});
$routeProvider.when('/presave-trsn',
{
templateUrl: 'templates/PreSaveTransaction.html',
controller: 'PreSaveTrsnController'
});
});
now inside my first controller is the presave function, which is empty since I don't know what to do with it so that I can send the transaction data to the next controller+view:
investingApp.controller('StockTransactionController',
function TransactionController($scope, $http, $location, $compile, $timeout, transactionDataService, dateFilter) {
// define some default variables
$scope.trsn = {};
$scope.trsn.symbol = "";
...
$scope.preSaveTrsn = function(trsn, formAdd) {
// what to put in here to transfer data to next controller????
};
and then my last controller, I have also nothing in there yet since I can't receive any data....but basically what I want to inject is the transaction data (trsn) which comes from 1st form/controller.
investingApp.controller('PreSaveTrsnController',
function MenuController($scope, $http, trsn) {
console.debug(trsn);
});
Does I have to put something inside the routeProvider somehow? ...or does I have to fill in something special inside the preSaveTrsn function inside my 1st controller??? I'm quite confused with this since all example I find are for saving right away to database, but I can't do that the way I build my app, it really has to be on the second controller for few reasons which I don't think I have to explain here.... Thanks for any help given :)
You may create a lightweight service - value
angular.module('investingApp').value('MySharedValue', {});
And then inject it in both controllers:
TransactionController($scope, $http, $location, $compile, $timeout, transactionDataService, dateFilter, MySharedValue)
And just to assign your shared value to it
$scope.preSaveTrsn = function(trsn, formAdd) {
MySharedValue.trsn = trsn;
};
There are 2 ways to achieve it. First is to declare your model object on $rootScope or on a scope which is parent to both of these controller scope. This way the data gets shared and the changes are available to both controller, irrespective of who makes it.
The second better approach is to create a service which tracks the model update. Inject this service into both the controller. Any controller can ask ask for the model from the service and update it. Since services are singleton, the model changes are shared across controller.
Like
angular.module("myApp",[]).factory('transactionService',[function(){
var service={};
var model={};
service.preSaveTrsn = function(trsn, formAdd) {
//set model here
};
service.getPreSaveTrsn=function() {
return model;
}
return service;
}]);

Resources