nest ng-view inside a form - angularjs

given the controller
function ctl($scope, $http) {
$scope.postForm = function() {
console.log("submitting form")
}
}
and the view
<form name="pform" ng-show="!error.Show">
<div ng-view></div>
<button type='button' value='Save' ng-click="postForm()" />
</form>
The controller method postForm doesn't get called, however, if i move the form tag into the view the method is called. Is there a reason that this doesn't work as I expect it to? Is there another way to accomplish the goal of sharing the form controls across different views?
Update
my module and routeProvider are configured like this:
angular.module("profilemodule", [])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when("/info", { templateUrl: '/partials/profile/info.html', controller: ProfileController })
.when("/user", { templateUrl: '/partials/profile/user.html', controller: ProfileController })
.when("/introduction", { templateUrl: '/partials/profile/editor.html', controller: ProfileController })
.otherwise({ redirectTo: '/info' });
}]).run(function ($rootScope, $location) {
$rootScope.location = $location;
})
and the page includes some nav elements which are set based on the location service like so:
<div class="row">
<div class="offset2 span10">
<ul class="nav nav-pills">
<li ng-class="{active: location.$$path.substring(0, '/info'.length) == '/info'}"><a href="#/info" >Information</a></li>
<li ng-class="{active: location.$$path.substring(0, '/user'.length) == '/user'}"><a href="#/user" >User</a></li>
<li ng-class="{active: location.$$path.substring(0, '/intro'.length) == '/intro'}"><a href="#/intro" >Introduction</a></li>
</ul>
</div>
</div>
<form name="pform" method="POST" ng-show="!error.Show">
<div ng-view></div>
<button type='button' value='Save' ng-click="postForm()" />
</form>
the ng-class statements works perfectly, is it because I've set the location property of $scope in the module's run method?
thanks,
jason

ng-view with routing creates a new scope with the controller, and you can't reach a child scope. Your submit action lies in the parent scope and the form data lies in the child scope (created by ng-view).
If you want to use common form controls, you can use ng-include, this directive gets template it and renders that in the current scope.
Move your form controls to a new template, then include them in all of your forms.
API reference:
http://docs.angularjs.org/api/ng.directive:ngInclude

Related

ng-model not working in ui-router nested view

I have the following code structure
index.html
<body ng-app="jobPortalApp" ng-controller="mainController">
<div ui-view></div>
</body>
then following is my homepage.html template
<div id=header>
</div>
<div ui-view>
<input type="text" ng-model="test">Test</input>
<input type="submit" ng-click="signup()">
</div>
<footer>
</footer>
my angular module file is as follows
var jobPortalApp = angular.module('jobPortalApp',['ui.router']);
jobPortalApp.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider
.otherwise('/');
$stateProvider
.state('home',
{
url:'/',
templateUrl: './templates/homepage.html',
controller: 'controllerHome'
})
}).controller('mainController', function(){});
following is my home controller
jobPortalApp.controller('controllerHome',function($scope, $http) {
$scope.test="";
$scope.signup = function() {
console.log($scope.test);
}
});
Required:
I want the changed value of test in my controllerHome after the user clicks on signup
Problem:
console.log outputs blank and if I remove $scope.test="";then outputs undefined. I want the changed value of test in my controller.
You usually shouldn't bind directly to $scope due to issues with prototypal inheritance. When trying to read a value from a child scope, if the value doesn't exist you end up reading from the parent scope. But as soon as you write, you write to the child scope. Does it work if you bind to an object instead?
$scope.data = {
test: ""
};
<input type="text" ng-model="data.test">Test</input>
As an alternative, you may also want to look at the controllerAs option for your route:
controllerAs: "ctrl"
Then in your controller:
this.test = "";
And in your template:
<input type="text" ng-model="ctrl.test">Test</input>

Controller outside ui-view

I want to use a unique controller inside and outside ui-view.
Using ng-inspector I see <div ui-view> has another instance of myController, not sure why.
<div class="container" ng-controller="myController">
::{{_path}}
<a ng-click="action()">action</a>
<div ui-view class="view"></div>
</div>
app.controller("myController",function ($scope) {
$scope.action = function(){
$scope._path= "changed";
}
});
The result of this issue is if I click on <button ng-click="action()">action</button> I see the changes in _path, if the same button is inside ui-view, _path doesn't changes. How can I make this work?
When you define your state you can specify the controller you want to use inside your view as follows:
$stateProvider.state('myState', {
url: '/my-state',
templateUrl: '/templates/my-state.html',
controller: 'myController'
});
Hope this helps.

Angular: Why Won't Model Update Outside Of View In Same Controller?

I have found a number of posts talking about models/views not updating, but I still can't figure this out. I'm new to Angular, btw so I suspect this is noob issue.
I have the below Angular app.
When the text input test_var is edited, the edited value isn't updated in the sidebar, but it is in the view. Why and how do I fix it?
This works when I don't use views and routes.
I've tried a sidebar controller, but no difference. I've tried $rootScope, which partially worked (it broke other functionality), but I'd prefer not to use a global scope.
Thanks for taking a look.
HTML
<body>
<div ng-app="rxApp" ng-controller="WizardCtrl">
<div class="ng-view">
</div>
<div class="sidebar">
<span ng-bind="test_var"></span>
</div>
</div>
</body>
View (One.html)
<input ng-model="test_var" />
<span ng-bind="test_var"></span>
Controller
rxApp.controller( 'WizardCtrl', function ( $scope, $http, $routeParams, $location, FileUploader ) {
$scope.test_var = 'please work!';
)};
Routes
rxApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/one', {
templateUrl: 'templates/one.html',
controller: 'WizardCtrl'
}).
when('/two', {
templateUrl: 'templates/two.html',
controller: 'WizardCtrl'
}).
otherwise({
redirectTo: '/one'
});
}
]);
Controllers are disposed when transmuting routes.
As for Best Practice you should create a Service to handle that data. You should not use controllers to carry data between views. In your case, the problem is Controllers are disposed when transmuting routes.
See the angular docs on how to use controllers correctly. http://docs.angularjs.org/guide/dev_guide.mvc.understanding_controller
The problem is the making of model variables.
You have to have a dot in model. Make your model point to an object.
So in your controller do like this -
rxApp.controller('WizardCtrl',function($scope, $http, $routeParams,$location, FileUploader){
$scope.test ={
var : 'please work!'
};
)};
View (One.html)
<input ng-model="test.var" />
<span ng-bind="test.var"></span>
HTML
<body>
<div ng-app="rxApp" ng-controller="WizardCtrl">
<div class="ng-view">
</div>
<div class="sidebar">
<span ng-bind="test.var"></span>
</div>
</div>
</body>
To read more about scope go through this UnderStanding Scopes

ui router not activating the controller in template context

I have a template which would be resolved in ui-view as
<div class="row login" >
<div class="col-xs-12 col-sm-8 col-md-6 " ng-class="offSet">
</div>
</div>
Now The ui router state which resolves this template from templateUrl is
.state('login.register', {
url: "login/register",
views: {
"#": {
templateUrl: "/Account/Register"
},
controller: "loginController"
}
})
And the controller is :
ngApp.controller('loginController', ['$scope', '$state', function ($scope, $state) {
$scope.offSet = "col-lg-offset-3";
$scope.login = function () {
$state.go('dashboard.home');
}
}])
Now what I want is the ng-class should get applied as soon as the template resolves and rendered. But thats not happening . the ng-class is not getting applied if I dont provide ng-controller attribute .
However when I put the ng-controller='loginController' in my template as
<div class="row login" ng-controller="loginController">
<div class="col-xs-12 col-sm-8 col-md-6 " ng-class="offSet">
</div>
</div>
Then the class gets attached and I can see the effect on resulting dom.
But as far as ui router documentation says . the controlller gets attached to the dom as soon as the template is resolved .
Any idea why without ng-controller attribute its not working ????
You are almost there, solution here is surprisingly simple. Controller belongs to the view, in our case to "named" view, not to the cluster views:
.state('login.register', {
url: "login/register",
views: {
"#": {
templateUrl: "/Account/Register"
controller: "loginController" // here it will be used
},
//controller: "loginController" // just skipped
}
})
In case we'd like to reuse one controller for more named views, we just repeat its definition for each of them...

ui-router rendering ui-views in view templates

Just checking an approach for ui-router. Was sure it could do this but hitting some friction. I want my third template to render inside my 2nd template - but my controller is not even initialized for my 3rd state unless I define my ui-view in my 1st template.
Example code
Template 1 This is rendered from an MVC view
<div class ="animate-container" ng-app="uiRouter-Browse">
<div class="products-slide-animate" ui-view="cat1">
<div>
<div><a ui-sref="cat1({id:1})">1</a></div>
<div><a ui-sref="cat1({id:2})">2</a></div>
<div><a ui-sref="cat1({id:3})">3</a><div>
</div>
</div>
</div>
Template 2
<div>
<div class="row all-categories-wrapper">
<div class="col-xs-12 list-item">
<a href="#/" class="parent">
<i class="chevron-left"></i>
<div>All Categories </div>
</a>
</div>
</div>
</div>
<!--want 3rd template to render here -->
<div ui-view="cat2" class="products-slide-animate" autoscroll="false">
<div class="cat2-wrapper" ng-repeat="cat1 in data.Cat1s">
<div class="row">
<div class="col-xs-12 list-item">
<a ui-sref="cat2({id:{{cat1.ID}}, name:'{{cat1.UrlEncodedName}}'})">
<div class="list-item-text">{{cat1.Name}}</div>
<i class="chevron-right"></i>
</a>
</div>
</div>
</div>
</div>
Template 3
<div>
//some content to render
</div>
My ui-router script
var browse = angular.module('uiRouter-Browse', ['ui.router', 'ngAnimate'])
.run(
['$rootScope', '$state', '$stateParams',
$rootScope.$on('$stateChangeSuccess',
function (event, toState, toParams, fromState, fromParams) {
console.log(toState.name);
console.log(fromState.name);
}
);
}]);
browse.config(
['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider
.otherwise('/');
$stateProvider
.state('cat1', {
url: '/cat1/:id?name',
views: {
'cat1': {
templateUrl: '/Template1.html',
controller: //Get some data and return
}
}})
.state('cat2', {
url: '/cat2/:id?name',
views: {
'cat2': {
templateUrl: '/Template2.html',
controller: //Get some data and return
}
}
});
}]);
Most if not all of the examples I see the entire ui-view is replaced, as opposed to partially being replaced - i.e. the rendering of template 3 in the ui-view in template 2.
So when click on the cat 1 links from template 1, it transitions to the next state, the controller is invoked and my animations are pretty.
When I click on a cat2 link, my state is invoked correctly but the controller is not fired. I then just animate back to my previous view/state.
If I place a ui-view="cat2" div in template 1 then the controller fires and my template renders. I just would like it to render within the ui-view in template2.
Thanks
While not sure if it will really suite to your needs, the reason and solution is in a different state definition, we need state nesting. We simply cannot have two "totally" independent states, and try to inject one into another. We have to make one of them Parent and one to be a Child:
Current scenario:
$stateProvider
.state('cat1', {
...
}})
.state('cat2', {
...
});
Both states are in this snippet on the same "root" level. If we would like to nest the cat2 into cat1 they must be defined like this:
$stateProvider
.state('cat1', {
... // this is a parent
}})
.state('cat1.cat2', {
... // this is a child
});
That will lead to url for a (sub)state cat2 to be built from both parent and its own:
#/'/cat1/:id/cat2/:id?name&nameurl',
but if we do not need Parent url part and its parameters we can use absolute url:
.state('cat2', {
url: '^/cat2/:id?name',
See:
Methods for Nesting States
Absolute Routes (^)

Resources