Angularjs custom component vs ngSwitch directive compilation order - javascript

There is a following code snippet:
<my-header></my-header>
<div ng-switch="$ctrl.page">
<div ng-switch-when="1"><component1></component1></div>
<div ng-switch-when="2"><component2></component2></div>
<div ng-switch-when="3"><component3></component3></div>
</div>
I want that component myHeader would be constructed before ngSwitch directive takes an action. Now component1 is constructed before myHeader.
Routing represents following code:
$stateProvider
.state({
name: 'myApp',
url: '/',
component: 'loader',
})
.state({
name: 'myApp.pages',
url: 'pages/{id:int}',
component: 'loader'
});
$urlRouterProvider.otherwise('/pages/1');

You can achieve this by exposing your controller in the link function inside the myHeader directive.
With that, you can easily add variables to the controller and control the visibility of the ng-switch div with ng-if. Check the code snippet down here.
Ah, don't forget to add ng-cloak to the div containing the ng-switch directive.
angular
.module('app', [])
.controller('TestController', function($scope) {
this.page = 1;
})
.directive('myHeader', function () {
return {
link: function (scope, element, attrs) {
// With element.controller() we can reach the controller that is wrapping our directive. Then, we can simply set the headerIsLoaded variable to true.
element.controller().headerIsLoaded = true;
},
scope: true,
templateUrl: 'my-header.html'
}
});
<div ng-controller="TestController as ctrl">
<my-header></my-header>
<!-- Add a visual feedback so user knows the components are being loaded -->
<div ng-if="!ctrl.headerIsLoaded">
Loading...
</div>
<!-- If ctrl.headerIsLoaded is set to true, the ng-switch will appear -->
<div ng-if="ctrl.headerIsLoaded"
ng-cloak>
<div ng-switch="ctrl.page">
<div ng-switch-when="1">
Page 1
</div>
<div ng-switch-when="2">
Page 2
</div>
<div ng-switch-when="3">
Page 3
</div>
</div>
</div>
</div>

Related

How to use ng-switch as a router for my pages with ngRoute & ngView?

Here is the highlevel skeleton of my Angular SPA. My application is about college degree offerings. In that engineering page has a separate left nav which is currently built on ng-switch which i want to convert as route. How do i do that just using angular's native routing angular-route.js?
**app.js**
(function(){
var app=angular.module("myCollege",['ngRoute']);
app.config(['$routeProvider','$locationProvider',
function($routeProvider,$locationProvider) {
$routeProvider
.when('/', {
templateUrl:"app/views/home.html",
controller:"homeController",
}
.when('/engg', {
templateUrl:"app/views/engineering.html",
controller:"engineeringController",
})
.when('/med', {
templateUrl:"app/views/medical.html",
controller:"medicalController",
})
}]);
I have left nav in engineering.html using ng-switch which i want to
convert as sub-route of the application.This left nav of engineering
page is not inside of ngView. How do i acheive this using angular's
native ngRoute/angular-route?
**engineering.html**
<div nav ng-switch on="pagename()">
<div ng-switch-when="Civil Engineering">
<div civil-directive> </div>
</div>
<div ng-switch-when="Computer Engineering">
<div computer-directive> </div>
</div>
<div ng-switch-when="Nano Engineering">
<div nano-directive> </div>
</div>
<div ng-switch-when="Electrical Engineering">
<div electrical-directive> </div>
</div>
</div>
EngineeringController.js
(function() {
var app =angular.module("collegeApp");
var engineeringController= functino($scope,$rootscope,$location)
{
$scope.pagename = function() {
return $location.path();
};
app.controller("engineeringController",['$scope','$rootScope','$location',engineeringController])
}());
The above logic is not working for me. Can someone tell me where i am doing the wrong?
Not a good practice but here's what you want to do if you want to use ng-switch:
In your html, as you write for example:
<!-- don't forget to reference your app and your controller -->
<button ng-click="goTo('/page1')">Go to page 1</button>
<button ng-click="goTo('/page2')">Go to page 2</button>
<div nav ng-switch on="pagename()">
<div ng-switch-when="'/page1'"></div>
<div ng-switch-when="'/page2'"></div>
</div>
<div ng-view> </div>
in js
Config your routes
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/page1', {
templateUrl: 'views/page1.html'
}).
when('/page2', {
templateUrl: 'views/page2.html'
}).
otherwise({
redirectTo: '/'
});
}])
and add the following in your controller:
$scope.pagename = function() { return $location.path(); };
$scope.goTo = function(page){
$location.path(page);
}
In the html above, ng-switch will use the $location.path() variable to know which view to display.
As I said this is not a good practice, because your controller isn't suppose to deal with routes.

Multiple views with nested states angular UI router

Is it possible to have multiple views that each contain nested states in Angular UI-Router?
For example, in the following could view1#main contain nested states? Lets say Main contains two page sections and view1#main contains a list that dynamically populates data in a view which I want to nest.
HTML:
<div class="main-container">
<div ui-view="view1">
<!--this is inside the template for view1-->
<div class="myList">
<!--ng-repeat each with a click setting the nested view-->
</div>
<div ui-view>
<!--this would be another template that -->
<!--changes based on the click from the ng-repeat -->
</div>
</div>
<div ui-view="view2"></div>
</div>
JS:
.state('main', {
url: '/main',
controller: 'MainCtrl',
views: {
'': {
templateUrl: 'views/main.html'
},
'view1#main': {
templateUrl: 'views/view1.html',
controller: 'MainCtrl'
//nested states in here
},
'view2#main': {
templateUrl: 'views/view2.html',
controller: 'SecondCtrl'
}
}
}

Angular directive attributes not being passed into scope

my angular directives' arguments aren't getting passed into the scope:
app.directive('sectionLeft', function() {
return {
restrict:'E',
scope: {
sectionContent: '=',
sectionImg: '='
},
templateUrl: 'partials/section_left.html'
};
});
app.directive('sectionRight', function() {
return {
restrict:'E',
scope: {
sectionContent: '=',
sectionImg: '='
},
templateUrl: 'partials/section_right.html'
};
});
They're called from here:
<div ng-repeat="content in data.home">
<section-left ng-if="$even" sectionContent="{{content}}" sectionImg="http://placehold.it/700x450"></div>
<section-right ng-if="$odd" sectionContent="{{content}}" sectionImg="http://placehold.it/700x450"></div>
</div>
and look like this:
<div class="section">
<div class="container">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">
{{sectionContent}}
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<img class="img-responsive" src="{{sectionImg}}">
</div>
</div>
</div>
</div>
The result is just a blank space with no content, but I can see the attributes getting set on the directive element. What's going on?
Thanks in advance!
Need to remove the {{}} to pass scope variables to directive using = in isolated scope.
section-content="content"
This will imply that the 2 way binding will be to a parent scope variable named content

Nested views inside angular ui bootstrap modal

Here is the entrypoint of my angularjs application. What I'm trying to create is an modal with multiple views.
(function() {
'use strict';
angular
.module('app', ['ui.router', 'ui.bootstrap'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('modal', {
url: '/modal',
onEnter: ['$stateParams', '$state', '$modal', function ($stateParams, $state, $modal) {
$modal.open({
templateUrl: 'partials/modal.html',
backdrop: 'static'
});
}]
})
.state('modal.models', {
url: '/models',
templateUrl: 'partials/modal.models.html'
});
})
.run(function ($rootScope) {
$rootScope.$on("$stateChangeError", console.log.bind(console));
});
}());
and this is the main view
<!-- Modal -->
<div id="myModal">
<div class="modal-header">
<h2>Select your own car</h2>
</div>
<div class="modal-body">
<h4>Brands</h4>
<a ui-sref="modal.models">Models</a>
<div ui-view></div>
</div>
</div>
My problem is that when I click on the link ui-sref nothing happens. Why ui-router doesn't work inside a modal? I should pass in the second view that is the following named modal.models.html
<div>
<h1>Hello</h1>
</div>
For those like me that stumble along later, here's another path:
This plunker uses a simple CSS modal (rather than the fancy ui-bootstrap one) to accomplish the same end result --with the additional perk of 'sticky states' that persist underneath the modal interaction. Note that this supports substates within the modal in a uirouter-kosher way.
$stateProvider.state('modal', {
url: '/modal',
views: {
'modal': {
templateUrl: 'modal.html'
}
}
});
$stateProvider.state('modal.substate', {
url: '/substate',
template: '<h3>I\'m a substate in a modal'
});
(Credit to #christopherthielen for the example code.)
<script type="text/ng-template" id="modal.html">
<div class="modal-overlay fade">
<div class="modal-content">
<h2>Modal</h2>
This modal has a substate. <a ui-sref=".substate">Activate it</a>
<div ui-view></div>
<a ui-sref="app">Back to the app...</a>
</div>
</div>
</script>
In my own troubleshooting, the problem with the 'injected-onEnter' pattern detailed in the ui-router FAQ --which your code follows-- is that the ui-views within the injected template seem to be no longer visible/available to ui-router. Alas! Good thing there's not much required to simply roll-your-own modal window.

angular.js two directives, second one does not execute

I have two directives defined in an angular.js module. The HTML element that is declared first executes its directive, but the second HTML element that uses the other directive does not execute it.
Given this HTML:
<div ng-app="myApp">
<div ng-controller="PlayersCtrl">
<div primary text="{{primaryText}}"/>
<div secondary text="{{secondaryText}}"/>
</div>
</div>
and this angular.js code:
var myApp = angular.module('myApp', []);
function PlayersCtrl($scope) {
$scope.primaryText = "Players";
$scope.secondaryText = "the best player list";
}
myApp.directive('primary', function(){
return {
scope: {
text: '#'
},
template: '<h1>{{text}}</h1>',
link: function(scope, element, attrs){
console.log('primary directive');
}
};
});
myApp.directive('secondary', function(){
return {
scope: {
text: '#'
},
template: '<h3>{{text}}</h3>',
link: function(scope, element, attrs){
console.log('secondary directive');
}
};
});
The resulting HTML is only the "primary" directive, and the "secondary" directive does not render:
<div ng-app="myApp" class="ng-scope">
<div ng-controller="PlayersCtrl" class="ng-scope">
<div primary="" text="Players" class="ng-isolate-scope ng-scope">
<h1 class="ng-binding">Players</h1>
</div>
</div>
</div>
The console output verifies this as well, as only the "primary directive" text is output.
Then if I switch the order of the primary and secondary elements, the secondary directive is executed and the primary directive is not:
<!-- reversed elements -->
<div secondary text="{{secondaryText}}"/>
<div primary text="{{primaryText}}"/>
<!-- renders this HTML (secondary, no primary) -->
<div ng-app="myApp" class="ng-scope">
<div ng-controller="PlayersCtrl" class="ng-scope">
<div secondary="" text="the best player list" class="ng-isolate-scope ng-scope">
<h3 class="ng-binding">the best player list</h3>
</div>
</div>
</div>
Why is this? What am I doing wrong?
div's are not void elements and require a closing tag.
<div ng-app="myApp">
<div ng-controller="PlayersCtrl">
<div primary text="{{primaryText}}"></div>
<div secondary text="{{secondaryText}}"></div>
</div>
</div>
Example

Categories