Directive to externalize view not working - javascript

I'm using pageslide directive in order to display a lateral sliding menu when I click on an icon.
This is the usual way to do it, and its working :
<div class="navbar-header">
<span ng-controller="slideController as s">
<a class="navbar-brand" href="javascript:void(0)"
ng-click="s.toggle()"><i class="fa fa-bars fa-lg"></i></a>
<div pageslide ps-open="s.isActive" ps-side="left">
<div style="padding:20px">
<h2>Hello Pageslide</h2>
<p>Put here whatever I want in the lateral menu</p>
<a ng-click="s.toggle()" class="button" >Close</a>
</div>
</div>
</span>
<a class="navbar-brand text-danger" href="javascript:void(0)">Balrog</a>
</div>
But I would lilke to make the menu content in an external template, so I'm trying this :
<div class="navbar-header">
<span ng-controller="slideController as s">
<a class="navbar-brand" href="javascript:void(0)"
ng-click="s.toggle()"><i class="fa fa-bars fa-lg"></i></a>
<menu-item isActive="s.isActive"></menu-item>
</span>
<a class="navbar-brand text-danger" href="javascript:void(0)">Balrog</a>
</div>
with this as menu.html :
<div pageslide ps-open="s.isActive" ps-side="left">
<div style="padding:20px">
<h2>Hello Pageslide</h2>
<p>Put here whatever I want in the lateral menu</p>
<a ng-click="s.toggle()" class="button" >Close</a>
</div>
</div>
also, here is the related controller :
'use strict';
angular.module('BalrogApp').controller('slideController', function(){
this.isActive= false; // This will be binded using the ps-open attribute
this.toggle = function(){
this.isActive= !this.isActive
}
});
and the <menu-item> directive :
angular.module('BalrogApp').directive('menuItem', function () {
return {
restrict: 'E',
templateUrl: "views/menu.html",
scope: {
isActive: '='
},
controller: 'slideController',
controllerAs: 's',
bindToController: true
}
});
So it's not working this way, maybe it is because the main view (including the <menu-item>) is itself included in the main page thanks to <ng-view> ?
Or maybe the pageslide-directive requires the <div pageslide ...> and its parent element to be on the same file ?
I can tell from the console that toggle() is called and changes isActive in both cases but it's not opening the menu with the directive version.
And also, adding ng-controller="slideController as s" to the root <div> with the pageslide attribute didn't change anything.
So how can I make this work with the menu in another file ?

Did you try to replace <div ng-include="menu.html"></div> with <div ng-include="'menu.html'"></div>. According to https://docs.angularjs.org/api/ng/directive/ngInclude, you have to wrap string constants in single quotes.

I highly recommend you not use ng-include. You can get the same approach using directive instead.
For example:
Menu html
<div pageslide ps-open="vm.checked" ps-side="left">
<div style="padding:20px">
<h2>Hello Pageslide</h2>
<p>Put here whatever I want in the lateral menu</p>
<a ng-click="vm.toggle()" class="button" >Close</a>
</div>
</div>
Directive:
function Controller() {
}
Controller.prototype.toggle = function() {
this.checked = !this.checked;
}
angular
.module('BalrogApp')
.directive('menuItem', function() {
return {
templateUrl: 'urltomenu.html',
restrict: 'E',
scope: {
checked: '='
},
controller: Controller,
controllerAs: 'vm',
bindToController: true
}
})
Main template
<div class="navbar-header">
<span ng-controller="slideController as s">
<a class="navbar-brand" href="javascript:void(0)"
ng-click="s.toggle()"><i class="fa fa-bars fa-lg"></i></a>
<menu-item checked="s.checked"><menu-item>
</span>
<a class="navbar-brand text-danger" href="javascript:void(0)">Balrog</a>
</div>
This approach give you more power. All the logic is inside the directive controller and you could reuse this element each time. The scope attribute checked is the "bridge" between your main template if change outside also change inside and also the other way.

Related

Can't show single item on click Angular

I'm getting the following error when I want to click on a link to show a single template (item):
WARNING: Tried to load angular more than once.
Link to screenshot: http://i.imgur.com/ZZDEA3J.png
Here is my templates.html code:
<div ng-repeat="template in filteredTemplates | filter:q" class="col-lg-4 col-md-6 col-sm-6 col-xs-12 portfolio-item">
<h4>
<a href="/edit/{{template.id}}" class="template-name" >{{ template.name }} </a>
</h4>
<p>{{ template.content.substring(0, 40) | htmlToPlaintext | removeNbsp }} ...</p>
<div class="row">
<div class="col-lg-6">
<div ng-repeat="license in template.licenses">{{license.name}} prijs <i class="fa fa-eur" aria-hidden="true"></i> {{license | setPrice}}</div>
</div>
<div class="col-lg-6">
<a ng-click="placeOrder(template)" class="btn btn-info" role="button"> Add to cart <span class="fa fa-cart-plus"></span></a>
</div>
</div>
</div>
app.js code:
//This will handle all of our routing
app.config(function($routeProvider, $locationProvider){
$routeProvider.when('/', {
templateUrl: 'js/templates/home.html',
controller: 'HomeController'
});
$routeProvider.when('/templates', {
templateUrl: 'js/store/templates.html',
controller: 'TemplateController'
});
$routeProvider.when('/edit/:id', {
templateUrl: 'js/store/template.html',
controller: 'GetTemplateController'
});
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
});
templateController.js:
template.controller('GetTemplateController', function ($scope, $routeParams, Template) {
console.log('here');
});
I suspect that the problem comes from the app.js file. Does someone knows what I'm doing wrong? Because I really can't figure it out
Taken from here:
You'll notice that if the app can't find a file (i.e., otherwise), then it will redirect to the root, which in this case loads the templateUrl. But if your templateUrl is wrong, then it will cause a recursion that reloads index.html loading angular (and everything else) over and over.
Seems like wrong template url is what's causing this.

same template coming up for two different angular directives

I have two separate angular directives that I'm calling (see below markup), but the last template is always the one that appears for both directives in the markup section below.
As you can see, I have the templateUrl set differently for both directives (in the directives section below), yet the last one in the markup section (attachment-modal.html) is always the one that appears.
If I make the download-modal.html the last one, then that template will appear for both directives. This is also seen by placing breakpoints in each of the directives. The first directive that you have defined in the markup, never gets executed even though it gets clicked on.
Both templates have different markup in them. If I comment out one of the directives, then the template associated with that directive comes out for both directives.
After manipulating the markup, no matter what I did, whichever directive was the latter one, is the directive that got executed.
It seems like I can't have two directives on the same web page because only the last one defined in the markup will get executed.
I tried it in both IE & Chrome.
What do I need to do to have the associated templates come out for each of the respective directives?
markup
<h3 class="panel-title">Check Deposit Header Information <download download-type="CK" download-id={{cdmCtrl.copiedRow.CheckDepositHeaderId}}>
</download> <attachment attachment-type="CK" attachment-id={{cdmCtrl.copiedRow.CheckDepositHeaderId}}>
</attachment>
</h3>
templates
download template
<p>For Testing Purpose: Download Type: {{downloadCtrl.attributes.downloadType}}</p>
<p>For Testing Purpose: ID: {{downloadCtrl.attributes.downloadId}}</p>
<div class="modal-header">
<h3 class="modal-title">File Download</h3>
</div>
<div class="modal-footer">
<div class="btn-toolbar pull-right" role="toolbar">
<div class="btn-group" role="group" >
<button type="button" class="btn btn-default" file-download download-type={{downloadCtrl.attributes.downloadType}} download-id={{downloadCtrl.attributes.downloadId}}>Download files</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" ng-click="$close()">Close</button>
</div>
</div>
</div>
upload template
<p>For Testing Purpose: Attachment Type: {{attachCtrl.attributes.attachmentType}}</p>
<p>For Testing Purpose: ID: {{attachCtrl.attributes.attachmentId}}</p>
<div class="modal-header">
<h3 class="modal-title">File Attachment</h3>
</div>
<div class="modal-body">
<input type="file" id="inpFile" file-model="myFile" />
</div>
<div class="modal-footer">
<div class="btn-toolbar pull-right" role="toolbar">
<div class="btn-group" role="group" >
<button type="button" class="btn btn-default" file-upload attachment-type={{attachCtrl.attributes.attachmentType}} attachment-id={{attachCtrl.attributes.attachmentId}}>Upload</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" ng-click="$close()">Close</button>
</div>
</div>
</div>
directives
.directive('attachment', ['$modal', function($modal) {
return {
restrict: 'E',
transclude: false,
replace: true,
template: '<a style="padding-right: 5px" class="pull-right" href="#" ng-click="open()"><i class="fa fa-files-o fa-lg" style="padding-right: 5px"></i>Attachment</a>',
link: function(scope, elem, attrs, controller) {
scope.open = function() {
$modal.open({
templateUrl: root + 'AccountingModule/modal/attachment/attachment-modal.html',
size: 'md',
backdrop: true,
controller: ['attributes', function(attributes) {
var viewModel = this;
viewModel.attributes = attributes;
}],
controllerAs: 'attachCtrl',
resolve: {
attributes: function() {
return attrs;
}
}
});
}
}
}
}])
.directive('download', ['$modal', function($modal) {
return {
restrict: 'E',
transclude: false,
replace: true,
template: '<a style="padding-right: 5px" class="pull-right" href="#" ng-click="open()"><i class="fa fa-files-o fa-lg" style="padding-right: 5px"></i>Download</a>',
link: function(scope, elem, attrs, controller) {
scope.open = function() {
$modal.open({
templateUrl: root + 'AccountingModule/modal/attachment/download-modal.html',
size: 'md',
backdrop: true,
controller: ['attributes', function(attributes) {
var viewModel = this;
viewModel.attributes = attributes;
}],
controllerAs: 'downloadCtrl',
resolve: {
attributes: function() {
return attrs;
}
}
});
}
}
}
}])
For the ng-click events in the directives, I needed to specify a different name for each scope opened.
For instance, openattachments & opendownloads for the scope.open functions since scope was a global variable and the last one always overwrote the first one.
template: '<a style="padding-right: 5px" class="pull-right" href="#" ng-click="openattachments()"><i class="fa fa-files-o fa-lg" style="padding-right: 5px"></i>Attachment</a>',

How to hide header tag from angular controller

I am building an angular application with multiple controllers.
Here is my index page:
<body ng-controller="BaseCtrl">
<div class="wrapper">
<header ng-show="HdrSection.ShowMenu">
<a ng-href="" class="show-list"><i class="fa fa-th-list">Option 1</i></a>
<a ng-href="" class="show-list"><i class="fa fa-th-list">Option 2</i></a>
<a ng-href="" class="show-list"><i class="fa fa-th-list">Option 3</i></a>
<a ng-href="" class="show-list"><i class="fa fa-th-list">Option 4</i></a>
</header>
<div class="container" ui-view>
</div>
</div> <!--wrapper div end-->
</body>
The pages of the application get rendered inside the div container. The first one gets loaded is the login page. I want to hide the header when login page is loaded and only show it whenever the page that is not a login page gets loaded. What's the best way to do that?
Should I hide it in the Login page controller?
Here is my login page:
<div id="login" class="main">
<div class="row">
<div class="col-md-2">
<img src="Images/Logo.gif" />
</div>
</div>
<div class="row">
<div class="col-md-10">
<form id="frmLogin">
<span class="prompt_text">Please enter your ID:</span>
<div class="input-group" style="width: 50%;">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input type="text" class="form-control" id="Username" ng-model="lc.user">
</div>
<br />
<input type="button" class="btn_main" value="Login" ng-click="Login()">
<br />
<span id="lblMsg" class="error_msg">{{lc.UserValidate}}</span>
</form>
</div><!--/.span12-->
</div><!--/.row-fluid-->
and here is a base controller for my index page:
(function () {
var app=angular.module("myApp", ["ui.router"]);
app.controller("BaseCtrl", ["$scope", BaseControllerFunc]);
function BaseControllerFunc($scope) {
//$('header').hide();
console.log($scope.HdrSection.ShowMenu);
$scope.HdrSection = { ShowMenu: false };
$scope.HdrSection.ShowMenu = false;
console.log($scope.HdrSection.ShowMenu);
}
})();
So far I tried 2 things:
using $('header').hide(); which works the first time page is opened but then I have no way to show the header again from any other child controller loaded by the page
and setting ng-show attribute of the header section to false in my base controller did not work as $scope.HdrSection.ShowMenu comes up as undefined
Can anyone help?
I load a number of different pages into the container div and each has its own controller. The only one I do not want header shown for is the login page
Try passing explicit the $scope form the controller injection as follow:
app.controller("BaseCtrl", ["$scope", BaseControllerFunc($scope)]);
function BaseControllerFunc($scope) {
...
}
})
Got it to work by changing my controller code to:
(function () {
var app=angular.module("myApp", ["ui.router"]);
app.controller("BaseCtrl", ["$scope", BaseControllerFunc]);
function BaseControllerFunc($scope) {
$scope = { ShowMenu: false };
}
})();
Now whenever the page loaded, the header is hidden and can be enabled by setting
$scope.parent = { ShowMenu: true };
from all other controllers

AngularJS: Set element to class active by default

I've created a custom tabbed element using the following code:
<div class="row step">
<div class="col-md-4 arrow active" ui-sref-active="active">
<a ui-sref="dashboard.create.key_elements" ui-sref-opts="{ reload: true }">
<span class="number">1</span>
<span class="h5">Key Elements</span>
</a>
</div>
<div class="col-md-4 arrow" ui-sref-active="active">
<a ui-sref="dashboard.create.questions" ui-sref-opts="{ reload: true }">
<span class="number">2</span>
<span class="h5">Questions</span>
</a>
</div>
<div class="col-md-4 arrow" ui-sref-active="active">
<a ui-sref="dashboard.create.publish" ui-sref-opts="{ reload: true }">
<span class="number">3</span>
<span class="h5">Publish</span>
</a>
</div>
</div>
As you can see I'm using ui-sref-active="active" to add a class of active to an element when it is clicked. My issue is getting the first element to display with a class of active when the page is first loaded as currently it only happens when an item is clicked. I've tried manually adding active to the first element but this seems to be ignored.
The problem is that the first route dashboard.create.key_elements is not the current route, so ui-router disables it as "active".
Solution:
Add another class in the CSS e.g. "newclassname" to have the same behavior of "active" class
Add ng-class to the first element conditioned to a variable in $scope and ng-click on the other elements so to disable it
In the JS:
$scope.firstActive = true;
$scope.changeFirst = function() {
$scope.firstActive = false;
};
EDIT:
Better yet, instead of dabbling with ng-click, you can simply inject the variable when you define the routes. E.g. from a snippet of my own code
.state('ordini', {
url: '/ordini/:pdv',
templateUrl: 'ordini/ordini.html',
controller: 'OrdiniController',
resolve : {
CartValue: ['$rootScope', '$stateParams', 'CartService', function($rootScope, $stateParams, CartService){
return CartService.getCartValue($rootScope.user.MachCode, $stateParams.pdv);
}]
}
See documentation

Custom elements inside AngularJS directive?

I'd like to avoid repeating myself with my page header as much as possible. So, I'm thinking doing something like this:
<header>
<title>Forms</title>
<actions>
<action ng-click="showNewFormModal()">New Form</action>
<action ng-click="showHelp()">?</action>
</actions>
</header>
which would desirably result in
<div class="page-header">
<div class="left">
<h3>Forms</h3>
</div>
<div class="right">
<a class="btn btn-default" role="button" ng-click="showNewFormModal()">New Form</a>
<a class="btn btn-default" role="button">?</a>
</div>
<div class="clearfix"></div>
</div>
As you can see, <header> contains custom elements, <title>, <actions>, and <action>, which are specific to only the <header> element.
Is such a thing possible in Angular? How would I accomplish this?
See this jsbin I put together which shows how it can be done with custom directives. I had trouble using the names header and title (though I'm almost positive it can be done), for the example, I've user my-header and my-title
Anyways, I've put together the first two elements, the rest will follow the same convention. You can also set up dependencies and scope on each directive, i.e. an action must be inside of an actions parent element
app.directive('myHeader', function() {
return {
restrict: "E",
transclude: true,
template: "<div class='page-header'><div ng-transclude></div></div>"
};
});
app.directive('myTitle', function() {
return {
restrict: "E",
transclude: true,
template: "<div class='left'><div ng-transclude></div></div>"
};
});
Your HTML will look like:
<my-header>
<my-title>Forms</my-title>
</my-header>
And the generated HTML will look like:
<my-header>
<div class="page-header">
<div ng-transclude="">
<my-title class="ng-scope">
<div class="left">
<div ng-transclude="">
<span class="ng-scope">Forms</span>
</div>
</div>
</my-title>
</div>
</div>
</my-header>

Categories

Resources