ionic custom directive not working in emulator - angularjs

I am building an application in Ionic 1 that uses custom directives. These work when testing in the browser, but do not show up in the emulator or on the iphone. I have seen that this has been an issue for others, but none of the suggestions have worked for me. Are there any suggestions out there for how to make a custom directive appear in the emulator (or, more importantly, on the iphone)?
Here is what I have tried. None of this has worked.
Moving the directives and controllers into the same file
Changing element directives to attribute directives (i.e <div my-directive></div> instead of <my-directive></my-directive>
Adding the CSS display: block to my element directives
Adding <ion-view><ion-content> tags around the directives, both within the directive templates, and then outside of the templates around the directives themselves in the parent templates.
Link to my project on github
And here are the essential pieces of code:
Directives
angular.module('starter.directives', [])
.directive('grid', function(GridFactory){
return {
restrict: 'AE',
templateUrl: '/templates/grid.html',
link: function(scope){
//does stuff
}
}
})
.directive('cell', function(){
return {
restrict: 'AE',
templateUrl: '/templates/cell.html',
scope: {
marker: '=',
isAlive: '=',
cellClick: '&'
}
}
})
Directive Templates
grid
<div class="row" ng-repeat="row in grid" style="height: 5vw" >
<div class="col gc-border gc-no-padding" ng-repeat="cell in row">
<cell is-alive=isAlive(cell.marker) marker=cell.marker neighbors = cell.neighbors cell-click=cellClick(cell)></cell>
</div>
</div>
cell
parent template
<ion-view view-title="Play">
<ion-content>
<div class="card">
<p>It rebuilt 2!</p>
<grid></grid>
</div>
<div class="button-bar">
<a class="button button-calm" on-tap="step()">Step</a>
<a class="button button-calm" on-tap="play()">{{isPlaying ? "Pause" : "Play" }}</a>
<a class="button button-calm" on-tap="clear()">Clear</a>
</div>
</ion-content>
</ion-view>

For the templateUrl in your directives you have the following:
.directive('grid', function(GridFactory){
return {
restrict: 'E',
templateUrl: '/templates/grid.html',
link: function(scope){
scope.grid = GridFactory.makeGrid(20,20);
scope.alive = [];
...
Remove the forward slash:
templateUrl: '/templates/grid.html', to
templateUrl: 'templates/grid.html', and for the rest of the templateUrl's.

Related

Passing variables to directive

I'm hoping someone can help me get my head around passing a variable into a directive. I've looked at other answers to what seem like similar questions to mine, but none seem to apply directly and/or I don't understand them.
So, my problem is that I have a toolbar that I want to be able to have access to variables found in different controllers. Not sure if this is even possible.
This is my directive (the scope and link options are all wrong, so they are here just for show):
.directive('toolbar', function(){
return {
restrict: 'E',
scope: {
page: '='
},
templateUrl: '/templates/toolbar.html',
link: function(scope, elem, attrs) {
scope.page = vm.page;
},
replace: false
};
})
I want to use it once in index.html, like this:
<body ng-app="app" ng-cloak layout="column">
<div layout-align="center center" layout-margin flex="50">
<img src="/images/logo.png" class="logo">
</div>
<toolbar page="{{vm.page}}"></toolbar>
<md-content>
<div ui-view ng-view></div>
</md-content>
</body>
where vm.page is a variable found in the controller that drives the ui-view, which is set up like this...
angular
.module('app')
.controller('dogsCtrl', function(dogsFactory, sessionService,
searchService, locationService, adoptableService, toastService,
errorHandlerService, $document, $mdSidenav, $scope, $state, $q) {
var vm = this;
vm.page = 'Home';
vm.currentUser = sessionService.getUser(); ....
I need to be able to access vm.page and the vm.currentUser object in a sub-directive on the toolbar. The toolbar template looks like this:
<md-toolbar class="md-menu-toolbar" hide show-gt-xs>
<div layout="row" layout-align="space-between center">
<div class="page-title" flex hide show-gt-md>
{{ vm.page }}
</div>
<div class="main-menu">
<md-menu-bar>
<menu></menu>
</md-menu-bar>
</div>
<md-input-container class="search">
<md-select name='breed' ng-model="breed._id" placeholder="Select a breed" ng-change="vm.getDogDetail(breed._id)">
<md-option value="{{breed._id}}" ng-repeat="breed in vm.dbBreeds"> {{ breed.breed }}</md-option>
</md-select>
</md-input-container>
</div>
As it stands now, I have to repeat the toolbar directive on every page, but I would rather not do it that way. Is this possible?
It should be like this
<toolbar page="vm.page"></toolbar>
because the page is two way binding.
OR
change the page scope type to this
restrict: 'E',
scope: {
page: '#'
},

How to communicate between sibling directives/components in angular 1.5

What is the best way to communicate between angular 1.5 sibling components and/or directives.
I am using angular material.
I am using ui-router.
I am trying to keep my components and directives separate and not dependent on each other.
I would like to refactor, where appropriate, my directives into .component() modules.
I have a navbar that I have separated into a directive (navBar). In that navbar, I have a search bar that I would like to filter a list. The list is in a sibling directive.
Originally I had the navbar directive(and tried to use it as .compontent()) outside of the scope of MainCtrl as defined by ui-router. This seemed to make sense to me as the navbar would be relatively consistent throughout the application.
I deferred to putting it inside the scope of MainCtrl where I can then bind properties from MainCtrl to elements in my navBar directive. This seems wrong as now the navBar and fileBrowser are coupled with the MainCtrl.
Other options I was looking into:
Using and scope.$watch() to define properties on the parent component from the child component navBar. Then in the other child component, fileBrowser, using scope.$watch() to watch for these changes in the parent component and respond accordingly.
Using a service to store data and pass data.
Using $emit, $broadcast events.
What is the best solution in this situation to keep my directive/components separate? What is the best/cleanest/recommended way to communicate between sibling directive/components?
This state is initiated by ui-router
main.component.js
angular.module('glossa')
.component('mainComponent', {
controller: MainCtrl,
controllerAs: 'vm',
transclude: true,
templateUrl: 'app/main/main.html'
});
function MainCtrl($scope, nodeSrvc, fileSrvc) {
var vm = this;
vm.selectedFile = {};
vm.fileList = [];
vm.searchText = '';
vm.filteredFiles = [];
activate();
function activate() {
buildFileList();
}
/**
* Queries for all files in db.
*/
function buildFileList() {
fileSrvc.queryAllFiles().then(function(docs) {
vm.fileList = docs;
});
}
}
main.html
//where the input where I filter the list
<navbar-directive></navbar-directive>
<div flex layout="row" >
//where the list is located
<file-browser layout="column"></file-browser>
<tabbar></tabbar>
</div>
<drawer-directive></drawer-directive>
I would like navbar to filter a list located in the sibling directive or component filebrowser
navbar.directive.js
angular.module('glossa')
.directive('navbarDirective', navBarDirective);
function navBarDirective(fileSrvc) {
var directive = {
restrict: 'E',
replace: true,
controller: NavbarCtrl,
controllerAs: 'navVm',
templateUrl: 'components/navbar/navbar.html',
bindToController: true
};
return directive;
}
navbar.html
<md-toolbar
layout="row"
class="nav-content primary-bg"
md-whiteframe="1"
md-selected-nav-item="currentNavItem"
nav-bar-aria-label="navigation links">
<span flex></span>
<div class="md-toolbar-tools">
<md-input-container md-no-float flex >
<form ng-submit="vm.searchSubmit()">
<input ng-model="vm.searchText" placeholder="Search...">
</form>
</md-input-container>
</div>
</md-toolbar>
This is where the list I'd like to filter is located.
filebrowser.js
angular.module('glossa')
.directive('fileBrowser', fileBrowser);
function fileBrowser() {
var directive = {
restrict: 'E',
templateUrl: 'components/filebrowser/filebrowser.html'
};
return directive;
}
filebrowser.html
<md-sidenav
md-component-id="left"
md-is-locked-open="true"
layout="column">
<md-content>
<md-list flex>
<md-list-item ng-repeat="file in vm.filteredFiles = (vm.fileList | filter: vm.searchText)" class="md-2-line">
<md-item-content md-ink-ripple layout="row" layout-align="start center">
<div class="md-list-item-text" layout="column">
<h3>{{file.name}}</h3>
<p>Preview of first few lines of a baseline</p>
</div>
</md-item-content>
</md-list-item>
</md-list>
</md-content>
</md-sidenav>
To communicate berween sibling components use bidirectional binding:
angular.module('glossa')
.directive('navbarDirective', navBarDirective);
function navBarDirective(fileSrvc) {
var directive = {
//Use bi-directional binding
scope: {
searchText: '='
},
restrict: 'E',
replace: true,
controller: NavbarCtrl,
controllerAs: 'navVm',
templateUrl: 'components/navbar/navbar.html',
bindToController: true
};
return directive;
}
HTML
<nav-bar-directive search-text="main.searchText">
</nav-bar-directive>
<sibling-component search-text="main.searchText">
</sibling-component>

angularjs directive - transclude non working as expected

I'm writing a submenu directive, but I'm unable to use transclude properly for some reason. I've read and watched some videos, but it still doesn't work on my app and I can't figure out why.
Here's how I call the directive:
<my-submenu>
<div ng-click="test()">Test</div>
<div ng-click="test2()">Test 2</div>
<div ng-click="test3(id, type)">Test 3</div>
<div ui-sref="test ({id: id})">Test 4</div>
</my-submenu>
and the directive js is:
{
link: linkFunction,
restrict: 'E',
replace: true,
transclude: true,
templateUrl: './directives/submenu.tpl.html'
}
and the directive template is:
<div>
<!-- Menu Icon -->
<div class="icon ion-plus"></div>
<!-- Menu -->
<div>
<div ng-transclude></div>
</div>
</div>
Now, I though that using transclude and telling the directive template where to transclude, I should be able to add content to the directive template as well as content where I call if from my parent, and have it compiled togheter, but it is not doing that.
The resulting compiled code is the following:
<my-submenu>
<div>
<div ng-click="test()">Test</li>
<div ng-click="test2()">Test 2</li>
<div ng-click="test3(id, type)">Test 3</li>
<div ui-sref="test ({id: id})">Test 4</li>
</ul>
</my-submenu>
and as you can see, the Icon before the transclude is gone and not displayed at all. Why?
What am I doing wrong with the transclude? thanks
I do this with the same way as your and it works properly..
My directive:
myApp.directive('toolbarItem', function() {
return {
transclude:true,
restrict: 'E',
scope: {},
link: function(scope, element, attrs) {
},
templateUrl:'/toolbarItem.html'
}
});
And my template:
<div class="item" ng-transclude></div>

AngularJS - Transclusion Containing Transclusion?

I am using Bootstrap UI's accordion directive. This uses transclusion under the hood. I have some logic that needs repeated, so I am trying to create a directive that wraps the accordian, which also uses transclusion.
<div>
<div accordion>
<div accordion-group is-open="isOpen">
<div accordion-heading>
<span class="glyphicon" ng-class="{'glyphicon-minus-sign': isOpen, 'glyphicon-plus-sign': !isOpen}"></span>
<strong>{{headerTitle}}</strong>
</div>
<div ng-transclude></div>
</div>
</div>
</div>
Here is the JavaScript:
application.directive('collapsePanel', ['baseUrl', function (baseUrl) {
return {
restrict: 'A',
templateUrl: baseUrl + 'content/templates/collapse_panel.html',
replace: true,
transclude: true,
scope: {
headerTitle: '#'
},
controller: ['$scope', function ($scope) {
$scope.isOpen = false;
}]
};
}]);
It should be as simple to use as:
<div collapse-panel header-title="Title">
{{scopeVariable}}
</div>
Assuming scopeVariable is in my controller, I would think its value would appear. From what I can tell, the scope belongs to the collapse-panel rather than the outer scope. It is almost like having nested transclusion directives is causing my problem.
Is there a trick to nesting transclusions like this?

Angularjs best practices for implementing multiple directives with common functionality

My page will have a growing list of directives that have common functionality. What would be the best way to implement that functionality keeping best practices and performance in mind.
For example:
Page will have 100 directives and each directive will have common events:
Show hidden layer on mouseover
Hide div > view and Show div > edit on click.
......
Template:
<div class="panel">
<div class="view">
<div class="edit-controls hidden">
Edit
</div>
<h3>{{......}}</h3>
<p>{{.....}}</p>
</div>
<div class="edit hidden">
<form>
........
</form>
</div>
</div>
Option 1. Directive:
appModule.directive('elemTest', [function() {
return {
restrict: 'E',
templateUrl: '.......',
replace: true,
controller: function($scope, $element) {
},
link: function(scope, element) {
element.on('mouseover', function() {
element.find(".edit-controls").show();
});
element.on('mouseout', function() {
element.find(".edit-controls").hide();
});
element.find(".edit").on('click', function(event){
event.preventDefault();
element.children(".view").hide();
element.children(".edit").show();
});
}
}
}]);
Option 2. Directive with no link functions but handle mouseover/out/click events with jQuery script snippet on the bottom of the page:
$(".panel").live('mouseover',function() {
.......
})
$(".panel").live('mouseout',function() {
.......
})
..........
Option 3. Directive with controller and ng-click instead of directives link function?
Option 4. ?
Using Angular 1.2.0
Option 4: Directives with support for ng-mouseover, ng-mouseout (mouseleave?) and an ng-click on the edit button.
In a nutshell, make your directive have a template which supports the functions:
In the template:
...
<div ng-mouseover="showEditControls = true" ng-mouseleave="showEditControls = false">
<div ng-show="showEditControls">
<button ng-click="edit()" />
</div>
</div>
...
In the directive:
...
controller: function($scope){
$scope.edit = function()
// do whatever the editor does
}
}

Resources