load parent scope before child scope using angular ui - javascript

I am using angularjs and the angular ui router to load nested templates. The child's controller inherits the parent's $scope for it's contents. This is all working fine except when I try to load the child scope as the initial view, the child scope is empty.
www.domain.com/products - parent view - works
www.domain.com/products/product-child view - works when navigating from parent.
When I try to load www.domain.com/products/product directly, the child template appears to load before the parent is complete leaving the child scope empty.
Here is the ui router info.
.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state('products', {
url: "/products",
templateUrl: "/views/products.html",
controller: "ProductsCtrl"
})
.state('products.product', {
url: "/:description",
templateUrl: "/views/product.html",
controller: "ProductCtrl"
})
});
What am I missing?
Parent View:
<section class="product-container">
<a ui-sref="products.product({description:product.description})" ng-repeat="product in products | orderBy : orderObjectBy(products,'active',true)" class="product" ng-click="" ng- class="{inactive:!filterProducts(product, products.keywords) && isFilterChecked() , 'selected- product':(product.selected)}" ng-style="{left: ((product.pos_left*360) + 'px'),top: ((product.pos_top*360) + 'px')}">
<img ng-src="http://www.tiempotimepiece.com/catalog/{{product.SmallImageUrl}}">
<p>{{product.description}}</p>
{{product.price | currency}}
<p>{{product.order}}</p>
</a>
<div ui-view></div>
</section>
Child View:
<div ng-repeat="product in items | filter: {description:description}">
Sku:{{product.Sku}}<br>
IdProduct:{{product.IdProduct}}<br>
price:{{product.price}}<br>
description:{{product.description}}<br>
SmallImageUrl:{{product.SmallImageUrl}}<br>
</div>
The child controller inherits the parent $scope by using $scope.$parent. When loading the child view as the initial page, the child view/controller appears to load before the parent has completed populating the scope.
What am I missing here? Thanks!
UPDATE: I do think a service is the quickest fix here and probably the best solution, but I am adding links to the Gists of the two controllers if anybody is interested in looking into this further to see if that is the best approach. These are a work in progress and have not been refactired at all and are frankly a mess at this point. There is a lot of crazy filtering and sorting going on.
Products (Parent) : https://gist.github.com/bennewton999/8257080
Product (Child) : https://gist.github.com/bennewton999/8257058

Ok, so I came in Monday morning with a fresh mind and realized I didn't need a different controller for this view at all. I just changed the controller to use the products controller for the product view and that was it.

Related

AngularJS loads constructor multiple times

my controller is loaded multiple times in my AngularJS 1.5 code:
<div ng-repeat="conditionForMultipleRows">
<div data-ng-if="$first">
<div co-my-component></div>
</div>
</div>
export function coMyComponent(): ng.IDirective {
return {
template: coMyComponentTemplateHtml,
controller: 'MyComponentController',
controllerAs:'$ctrl'
}
}
export class MyComponentController{
state: MyStateClass;
static $inject = [someServices]
constructor(someServices) {
document.getElementById("myComponent").addEventListener("myEvent", (ev: CustomEvent) => {
doStuff()
}
The HTML Part is only called once, so there should be no issue. Only my controller is loaded multiple times.
The angular.module only loads the controller once and the directive only once, so there is no issue. Also there is no other place where the controller or webcomponent is called in the code.
I'm not very familiar with AngularJS so you can also point out other parts if you see something wrong here. Please refer to a source if it was resolved there. I didnt find any helpful answer
Thanks in advance guys
Each time your directive is instantiated, it will received a brand new controller.
The ng-repeat directive instantiates a template once per item from a collection.
In your case, if conditionForMultipleRows is an array having four items inside, you will instantiate four times the template
<div data-ng-if="$first">
<div co-my-component></div>
</div>
Each template instance gets its own scope and own controller, thus calling the constructor four times.
The answer for my issue here is:
<div ng-repeat="conditionForMultipleRows track by $index ">
<div data-ng-if="$first">
<div co-my-component></div>
</div>
</div>
With adding track by $index, the controller of my component only loaded once.
Also learned that in a ng-repeat it should always be added a "track by". There are only a few egde cases where this isnt required. Correct me if I'm wrong

hide elements depending on the ui.router state nothing work at all

<section class="navbar" ng-controller="NavbarCtrl" ng-hide="$state.current.name === '/events'">
<div class="navbar__container">
</div>
</section>
I have this navbar and I want make it not show if I'm in the /events page. Everything is set, but nothing happens.
$stateProvider.state('/events', {
url: '/events',
templateUrl: '/admin/event/event.tmpl.html',
controller: 'EventCtrl'
});
What is the problem here? I can't figure out way is not working.
You can use isState filter with either ng-show or ng-hide.
ng-show="('a.b.1' | isState) || ('a.b.2' | isState)"
Your ng-hide doesn't work because your view doesn't know anything about $state.
To use $state in a view you need to assign it to scope variable in your controller.
$scope.$state = $state; // of course you need to inject it in your controller

How to hide show in Angular

I am beginner in angular js
HTML
<div ng-app="myapp">
<div ng-controller="maincontrol">
<div ng-show="!vis">show</div>
<div ng-show="vis">hide</div>
</div>
<div ng-view></div>
</div>
JS
var app = angular.module('myapp', ['ngRoute'])
app.controller('maincontrol', function ($scope) {
$scope.vis = true;
$scope.fun = function () {
if ($scope.user == "home" && $scope.pass == "home") {
console.log($scope.user, $scope.pass);
$scope.vis = false;
}
}
})
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'home.html'
})
.when('/contact', {
templateUrl: 'contact.html'
})
});
and also i have two html pages like
home.html
<div ng-controller="maincontrol">
<input ng-model="user"/>
<input ng-model="pass"/>
<div ng-click="fun()">
click
</div>
</div>
contact.html
<div>
contact
</div>
my expectation is after entering home into user and pass. if i click 'click' i need to show 'show' label instead of 'hide'. pls help me.
Each controller has its own scope, when you wrote $scope.vis=false on fun(), you actually created a new variable on maincontroler1 scope. If you expected this variable to affect the view which is binded to maincontroler scope, it won't happen.
I suggest 2 options:
You can use one controller for entire app (If you use same controller in two tags it will still create a new scope although it is the same controller), this way the fun() method that was called from the first view will change the boolean in the single controller and will affect the second view. Please note when you use ng-view you will have to get the variable from the parent.
So I used this code:
$parent.user
$parent.pass
Create this working plunker for you.
Share the vis boolean between 2 controllers using a service. You can
use this post for this option.
You can also use reach parent controller scope from child controller, that can be done if ng-view will be nested in the outer controller. You can use this post for option 3.

What is the difference between an ng-controller directive and a controller in the route?

I worked through the tutorial on the AngularJS website and I noticed that in at step 7, they change how a controller is introduced into the application. Initially, they use a directive:
<body ng-controller="PhoneListCtrl">
...
</body>
However, it later gets changed to use a controller attribute as part of an ng-route.
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
/* rest of routes here */
Here's the git diff where the change is made. Is there a difference between these two techniques?
Controller using a ng-controller directive:
A new $scope is created on ng-controller element.
Explicit view-to-controller connection
Visible with inspect element, etc
Controller in a route:
A new $scope is created per route on the ng-view element.
The controller can request dependencies defined in the route resolve.
Optional view-to-controller connection. Recommended to have a naming convention that maps routes to controllers to views.
One of well-known feature of Angularjs is Single-Page Applications.
If you assign ng-controller attribute directly on the page:
<body ng-controller="PhoneListCtrl">
...
</body>
you can't switch controllers easily for other tasks.
So, use route to switch controllers is one of important step in learning Angular Single-Page feature.
You can have same layout and one different element by using route and ng-view directive.
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/tablets', {
templateUrl: 'partials/tablet-list.html',
controller: 'TabletListCtrl'
}).
If '/phones'
<div ng-view></div>
will include your 'partials/phone-list.html' template
and set 'PhoneListCtrl' as div controller
The same:
If '/tablets'
<div ng-view></div>
will include your 'partials/tablet-list.html' template
and set 'TabletListCtrl' as div controller
This is the difference between two.
ng-view is the cause of the difference. You can't really do this
<div ng-view ng-controller="PhoneListCtrl">
As you'd need to change that controller as the route changed. So basically the router does that for you, and uses the controller you specified when you defined your routes.
You probably can do this:
<div ng-view>
and then in your template:
<div ng-controller="PhoneListCtrl">
and leave out the controller declaration in your routes. Which I suspect would have essentially the same effect, although I've never tried that. Probably better to go with convention here though.
In the 1st case the controller is directly on the page.
Once they change it, that controller is only on the page if the route is /phones otherwise it is some other controller based on some other route.
Yes - the change is this:
if you want to display a specific controller on the page, you can use
<body ng-controller>
BUT
if you want to do routing (application with more than one controller) - you will need to use routing + change the body to:
<body ng-view></body>

Global "App" controllers in AngularJS

I have noticed in a few tutorials and code examples floating around the internet developers using a global AppController in their applications and modules.
Is it best practice to create a global AppController in AngularJS?
I do see some benefits such as being able to handle events in a "global" scope such as:
app.controller('AppController', function($scope, $rootScope, $route, $location){
$rootScope.$on('$routeChangeStart', function(event, current, previous) {
console.log('Do something...');
});
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
console.log('Do something...);
});
});
are there any other advantages or disadvantages to this pattern?
Purely in context of situation. Let's take an example of dynamically changing title tags and page view:
.config(['$routeProvider','$locationProvider',function($routeProvider,$locationProvider){
$routeProvider.when('/', {
template: '/views/home.html',
title:'Home'
});
$locationProvider.html5Mode(true);
}]);
.controller('app', ['$scope','$route','$location',function($scope,$route,$location){
$scope.$on("$routeChangeSuccess",function($currentRoute,$previousRoute ){
$scope.title = $route.current.title;
$scope.page = $route.current.template;
});
}]);
Now both our title and page view are being dynamically loaded in through app level controller that wraps our application. This can be very useful.
<html lang="en" ng-controller="app">
<head>
<title>{{title}}</title>
</head>
<body>
<ng-include src="page"></ng-include>
</body>
</html>
Here's an example of when not to use it. Let's say one of our partial pages return data from an API:
<!-- search.html -->
<div ng-repeat="item in items">
{{item.title}}
</div>
And in our app level controller we are pulling data via broadcast:
$scope.$on('searchComplete',function(d){
$scope.items = d
});
That partial will show the data as we intended however - problems could arise when other child partials use items where scope is being overwritten.
<!-- other-search.html -->
<div ng-controller="OtherSearch" ng-click="search()">
<div ng-repeat="item in items">
{{item.title}}
</div>
</div>
In this partial, ng-click is guiding the users request. So if the app level controller already binded items in the parent, the user will see a list of items when toggling to this partial even if they never triggered the action of search().

Categories