Angularjs - Custom directive cannot access controller scope - angularjs

I am building a single page app with Angular JS. The problem is the custom directive mySlider cannot access the scope of the controllers I assign to the template. Is there a way to solve this problem? Here are my files
index.html
<script src="js/dishesapp.js"></script>
<div ng-view></div>
partials/dishestemplate.html
<div my-slider></div>
directives/slider.html
<div id="dishsliderholder">
<ul class="bxslider">
<li class="dishdetails" ng-repeat="dish in dishes">
<div class="item">
<div class="title">{{dish.name}}</div>
<div class="description">{{dish.description}}</div>
</div>
</li>
</ul>
</div>
dishesapp.js
var dishesApp = angular.module('dishesApp', ['ngRoute']);
dishesApp.config(function ($routeProvider) {
$routeProvider
.when('/', {templateUrl: 'partials/default.html'})
.when('/Noodles', {templateUrl: 'partials/dishtemplate.html', controller: 'NoodlesCtrl'})
.when('/Rolls', {templateUrl: 'partials/dishtemplate.html', controller: 'RollsCtrl'})
.when('/Pancakes', {templateUrl: 'partials/dishtemplate.html', controller: 'PancakesCtrl'})
.when('/Rice', {templateUrl: 'partials/dishtemplate.html', controller: 'RiceCtrl'})
.when('/FamilyStyle', {templateUrl: 'partials/dishtemplate.html', controller: 'FamilyStyleCtrl'})
.when('/Others', {templateUrl: 'partials/dishtemplate.html', controller: 'OthersCtrl'})
.otherwise({redirectTo: '/'});
});
dishesApp.controller('NoodlesCtrl', function ($scope, $http) {
$scope.mycategory = "Noodles";
$http.get("http://www.blabla.com/Data/dishes.php").success(function (response) {
$scope.dishes = response.records;
});
});
dishesApp.controller('RollsCtrl', function ($scope, $http) {
$scope.mycategory = "Rolls";
$http.get("http://www.blabla.com/Data/dishes.php").success(function (response) {
$scope.dishes = response.records;
});
});
……………..
dishesApp.directive('mySlider', function() {
return {
restrict: 'A',
templateUrl: 'directives/slider.html',
link: function (scope, element, attrs) {
angular.element( document.querySelector('.bxslider')).bxSlider();
angular.element( document.querySelector('#dishsliderholder')).css("background-size", getSliderHolderBackgroundSize());
}
};
});

I finally figured out the problem. The slider object was called before the DOM finish rendering so the slider shows nothing. I use $timeout to call the slider post render. Here is how I did it
dishesApp.directive('mySlider', function ($timeout) {
return {
restrict: 'A',
replace: true,
templateUrl: 'directives/slider.html',
link: function (scope, element, attrs) {
$timeout(function () {
angular.element(document.querySelector('.bxslider')).bxSlider();
angular.element(document.querySelector('#dishsliderholder')).css("background-size", getSliderHolderBackgroundSize());
});
}
};
});

Since the directive is not isolated, you can access all the controllers' scope variables inside a directive link function.
Your code is working. As #Rhumbori commented http://jsfiddle.net/w5mh927p/ is perfectly working.
Try adding a line inside link function: console.log(scope) and check what all is present on scope in your developer tools console. https://www.dropbox.com/s/q3tmgapcxn8e71p/Screenshot%202015-05-31%2002.17.33.png?dl=0

Related

blank <img src> custom directive in Angular JS and I was referring to this https://www.youtube.com/watch?v=R_okHflzgm0

I am new to angularjs and I was trying to create custom directive and for that I was following steps from https://www.youtube.com/watch?v=R_okHflzgm0 I did exactly what was shown here but for some reason img src is blank I dont know what is wrong in my code
//created new app
var myApp=angular.module('myFirstApp', ['ngRoute']);
//configured routing
myApp.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/home', {
templateUrl: 'views/home.html'
})
.when('/directory', {
templateUrl: 'views/directory.html',
controller: 'NinjaController'
}).otherwise({
redirectTo: '/home'
});
}]);
//custom directive
myApp.directive('randomNinja', [function(){
return{
restrict: "E",
scope: {
ninjas: '=',
title: '='
},
templateUrl: 'views/random.html',
controller: function($scope){
$scope.random = Math.floor(Math.random()*4);
}
};
}]);
//controller
myApp.controller('NinjaController', ['$scope', '$http', function($scope,$http){
$http.get('data/ninjas.json').then(function(response){
$scope.ninjas=response.data;
}, function(error){
console.log(error);
})
$scope.removeNinja=function(ninja){
var ninjaRemoved=$scope.ninjas.indexOf(ninja);
$scope.ninjas.splice(ninjaRemoved, 1)
}
$scope.addNinja=function(){
$scope.ninjas.push({
name: $scope.newNinja.name,
belt: $scope.newNinja.belt,
rate: parseInt($scope.newNinja.rate),
available:true
})
$scope.newNinja.name='',
$scope.newNinja.belt='',
$scope.newNinja.rate=''
}
//image links
Inspect view from browser
JSON data file
Home with custom directive and random view

AngularJS directive scope property doesn't render in directive view

I have a problem with scope property of directive that doesn't render want to render in directive view.
app.js
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl',
controllerAs: 'main'
})
main.js
angular.module('todayfmApp')
.controller('MainCtrl', ['$scope', function ($scope) {
this.formsetup = [];
this.formsetup.title = "Find Your Break";
}]);
mainController View - where Form Setup: {{main.formsetup.title}} is rendering properly
<h2>Form Setup: {{main.formsetup.title}}</h2>
<section class="home-banner">
<carousel-partial></carousel-partial>
<overlay-form formsetup="main.formsetup.title"></overlay-form>
directive
angular.
module('directives').
directive('overlayForm', function() {
return {
restrict: 'E',
scope: {
formsetup: '='
},
controller: [ '$http', '$scope',
function OverlayFormController($http, $scope) {
var self = this;
self.getResponseData = function(){
$http.get('data/form-data.json').then(function(response) {
self.formdata = response.data;
});
}
this.logResponseData = function() {
console.log(self.formdata);
}
this.getResponseData();
}
],
controllerAs: 'Ctrl',
bindToController: true,
templateUrl: 'scripts/directives/overlay-form/overlay-form.template.html',
};
});
Directive View
<div class="overlay-form">
<h3>{{formsetup.title}}</h3>
Problem is with template binding.It should be:(when you use controllerAs you need to refer view elements with the alias name)
<div class="overlay-form">
<h3>{{Ctrl.formsetup.title}}</h3>
</div>
And directive HTML code should be:
<overlay-form formsetup="main.formsetup"></overlay-form>
Please check Plunker for more understanding of how it works.

Angular ui-router: $stateParams empty inside my directive

In my angular app, I have created a custom directive for a navbar, which controller takes in $stateParams to access a variable called lang, as so:
.config(function($stateProvider, $urlRouterProvider, LANG) {
$urlRouterProvider
.otherwise('/' + LANG['EN'].shortName);
$stateProvider
.state('proverb-list', {
url: '/:lang',
templateUrl: 'components/proverb-list/proverb-list.html',
controller: 'ProverbListCtrl as vm'
})
.state('proverb-single', {
url: '/:lang/:proverbId',
templateUrl: 'components/proverb-single/proverb-single.html',
controller: 'ProverbCtrl as vm'
});
});
When I access the state proverb-list, the controller named ProverbListCtrl does see $stateParams.lang correctly, but my navbar directive cannot. When I console.log($stateParams) all I get is an empty object.
This navbar is outside my ui-view:
<navbar proverbial-navbar></navbar>
<div ui-view></div>
<footer proverbial-footer></footer>
Is that the problem? How can I access the actual $stateParams inside my directive?
EDIT: directive code below, as asked:
(function() {
'use strict';
angular
.module('proverbial')
.directive('proverbialNavbar', directive);
function directive() {
var directive = {
restrict: 'EA',
templateUrl: 'components/shared/navbar/navbar.html',
scope: {
},
link: linkFunc,
controller: Controller,
controllerAs: 'vm',
bindToController: true
};
return directive;
function linkFunc(scope, el, attr, ctrl) {
}
}
Controller.$inject = ['LANG', 'ProverbFactory', '$stateParams'];
function Controller(LANG, ProverbFactory, $stateParams) {
var vm = this;
vm.languages = LANG;
console.log($stateParams);
vm.currentLang = LANG[$stateParams.lang.toUpperCase()];
activate();
function activate() {
vm.alphabet = ProverbFactory.getAlphabet();
}
}
})();
You should not access $stateParams in this directive when it is independent of the state. Since your navbar is outside of the ui-view, its controller can be called before the ui-router has initialized the $stateParams of the state you are interested in. Remember that your navbar controller is called only once, when the navbar is initialized and not every time the state changes.
Alternative: What you can do is turn your currentLang field into a function. The function can retrieve the value from the $stateParams when needed:
vm.currentLang = function() { return LANG[$stateParams.lang.toUpperCase()] };
Make sure you change currentLang to currentLang() everywhere in your template.

Angularjs routing: TypeError: Cannot read property 'path' of undefined

I'm new to AngularJS. Can someone help me why the following routing will not work? I have a custom directive that submits a user form. After submission, it should navigate to the success page.(views/success.html).
I'm getting an error upon submission. TypeError: Cannot read property
'path' of undefined
If I simply try navigate to "/index.html#/success" on the address bar, it will not redirect to the success page, so I'm suspecting it is a routing issue but I can't seem to understand the cause of it. Any help would be greatly appreciated!
var myApp = angular.module('myApp', ['ngRoute', 'myControllers', 'loginDirective'])
.config(function ($routeProvider) {
$routeProvider.when("/home", {
templateUrl: 'index.html',
controller: 'myApp'
}).when("/success", {
templateUrl: 'views/success.html',
controller: 'myApp'
})
// If no route is selected then use the 'home' route.
.otherwise({ redirectTo: '/home' });
});
// Directive - Modifies HTML behaviour.
var myDirectives = (function () {
var myDirectives = angular.module('loginDirective', []);
// directive() is a factory method to create directives.
myDirectives.directive('login', function () {
return {
restrict: 'A',
scope: {
},
link: function ($scope, elem, attrs, ctrl, $location) {
$scope.submit = function() {
console.log("I clicked on submit");
$location.path("/success");
}
},
templateUrl: function (element, attr) { return 'views/loginForm.html' },
}
});
return myDirectives;
}());
// Controller - dispatches inputs and outputs.
var myControllers = (function () {
var myControllers = angular.module('myControllers', []);
// Controllers are defined by the controller function.
myControllers.controller('AppCtrl', ['$scope', '$routeParams','$location', function ($scope, $routeParams, $location) {
$scope.title = "Sign in";
}]);
return myControllers;
}());
index.html
<!DOCTYPE html>
<html>
<body ng-app='myApp' ng-controller="AppCtrl" class="container">
<div login></div> //custom directive
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-route.min.js"></script>
<script src="js/app.js"></script>
</body>
</html>
$location needs to be injected in the directive definition, not in the link
function, e.g.
// directive() is a factory method to create directives.
myDirectives.directive('login', ['$location', function ($location) {
...
}]);
Also you don't need to use a separate module for controllers, directive, etc. In other words, there only needs to be one angular.module('...') call
Your whole code can be simplified as
// define the app
var app = angular.module('myApp', ['ngRoute']);
// app configuration block
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.when("/home", {
templateUrl: 'index.html',
controller: 'myApp'
}).when("/success", {
templateUrl: 'views/success.html',
controller: 'myApp'
})
// If no route is selected then use the 'home' route.
.otherwise({ redirectTo: '/home' });
}]);
// definition block for 'AppCtrl' controller
app.controller('AppCtrl', ['$scope',
function ($scope) {
$scope.title = "Sign in";
}]);
// definition for 'login' directive
app.directive('login', ['$location',
function ($location) {
return {
restrict: 'A',
scope: {
},
link: function (scope, element, attrs) {
scope.submit = function() {
console.log("I clicked on submit");
$location.path("/success");
}
},
templateUrl: 'views/loginForm.html'
}
}]);

Angularjs - filter results from rest api based on value of textbox

OK - so I have the following service:
angular.module('myApp.services', ['ngResource'])
.factory('STLineup', function($resource){
return $resource('http://someapi.com?filters=location.eventInstance.slug:Slug,artists.tags:ArtistTags,location.name:LocationName',
{Slug: '#Slug', ArtistTags: '#ArtistTags', LocationName: '#LocationName'})
});
And the following controller:
angular.module('myApp.controllers', [])
.controller('MyCtrl1', ['$scope', 'STLineup', function($scope, stl) {
$scope.items = {};
stl.get({'Slug': ':xxxxx-2014', 'ArtistTags': ':electronic|grime', 'LocationName': ':Snakepit'},function(response) {
$scope.items = response.results;
});
$scope.changeCallback = function() {
stl.get({'Slug': ':xxxxxx-2014', 'ArtistTags': ':electronic|grime'},function(response) {
$scope.items = response.results;
});
}
}]);
And the following directive:
angular.module('myApp.directives', [])
.directive('appLineup', [function() {
return {
restrict: 'AEC',
scope: {
items: '=',
change: '&changeCallback'
},
link: function(scope, elem, attrs){
},
templateUrl: 'templates/lineup.html'
};
}]);
And the following template:
<input type="text" ng-model="LocationName" ng-change="change()" />
<br/>
<div class="item" ng-repeat="item in items">
<p class="title">{{item.name}}</p>
</div>
Which is added to the UI using the following:
<app-lineup items="items" change-callback="change()" />
PHEW!!
So - the initial data is being loaded in but the change event is never getting fired into? What am I doing wrong here?!
Here is the code in app.js;
angular.module('myApp', [
'ngRoute',
'ngResource',
'myApp.filters',
'myApp.services',
'myApp.directives',
'myApp.controllers'
]).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: 'MyCtrl1'});
$routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: 'MyCtrl2'});
$routeProvider.otherwise({redirectTo: '/view1'});
}]);
The change() function is declared in you controller's scope, but since your directive uses an isolate scope (i.e. one that doesn't prototypally inherit from its parent), it knows nothing about it.
You could pass it to the directive's scope like this:
<!-- The VIEW -->
<app-lineup items="items" change-callback="change()" />
/* The DIRECTIVE */
...
scope: {
...
change: '&changeCallback'
}
scope.change = function() {
Forgetting your $, which in turn is not allowing change() in your template to do anything.
scope.items = response.results;
Forgetting your $.

Resources