I have a sidebar directive in my web application with a set of values that bind to some model in another controller. When page loads, all the values are fetched and populated correctly. However when the model is updated from the controller, the event is not captured by the watch setup in directive.
Here is my sidebar html:
<div class="navbar-default sidebar" ng-controller="SettingsCtrl" role="navigation">
<div class="sidebar-nav navbar-collapse">
<ul class="nav in" id="side-menu" style="padding-left: 8px;">
<li ng-repeat="profile in profiles">
<label>
<input type="radio" ng-model="profile" name="name" value="{{profile.text}}"/>
{{profile.text}}
</label>
</li>
</ul>
</div>
</div>
Directive sidebar.js:
angular.module('webApp')
.directive('sidebar',['$location',function(Request) {
return {
templateUrl:'scripts/directives/sidebar/sidebar.html',
restrict: 'E',
replace: true,
scope: false,
link: function(scope, element, attrs){
scope.$watch('profiles', function(newValue, oldValue){
console.log(newValue + ' ' + oldValue);
}, true);
}
}
}]);
Here is my SettingsCrl controller:
angular.module('webApp')
.controller('SettingsCtrl', function($scope) {
$scope.profiles = [{text: "john"}, {text: "paul"}];
function someEvent(){
$scope.profiles.push({text: "hannah"});
}
});
I have tried to do watchCollection instead, but still no luck..
Related
I need a big favor. I have this ng-repeat directive
appTitan.directive('questionsAnswers', function() {
return {
restrict: 'E',
templateUrl: '/js/directives/questionsAnswers.html',
replace: true,
scope: {
questions: '=',
chosenAnswersArr: '='
},
link: function(scope) {
scope.chosenAnswers = function(selection) {
scope.chosenAnswersArr.push(selection);
};
}
};
});
And this is used accordingly in the template
<div class="question-answers__item__wrapper">
<div class="question-answers__item__question">
<h3>{{ questions.questionName }}</h3>
</div>
<div class="question-answers__item__answers">
<ul class="row">
<li class="col-sm-6" data-answer-item-id="{{questions.answerOne.isCorrect}}" ng-click="chosenAnswers(questions.answerOne.isCorrect)">
<p>{{questions.answerOne.value}}</p>
</li>
<li class="col-sm-6" data-answer-item-id="{{questions.answerTwo.isCorrect}}" ng-click="chosenAnswers(questions.answerTwo.isCorrect)">
<p>{{questions.answerTwo.value}}</p>
</li>
<li class="col-sm-6" data-answer-item-id="{{questions.answerThree.isCorrect}}" ng-click="chosenAnswers(questions.answerThree.isCorrect)">
<p>{{questions.answerThree.value}}</p>
</li>
<li class="col-sm-6" data-answer-item-id="{{questions.answerFour.isCorrect}}" ng-click="chosenAnswers(questions.answerFour.isCorrect)">
<p>{{questions.answerFour.value}}</p>
</li>
</ul>
</div>
</div>
and added in HTML like this
<li class="question-answers__item" ng-repeat="questions in quizData.questionAndAnswers" elem-height>
<questions-answers questions="questions" chosenAnswersArr="chosenAnswersArr"></questions-answers>
</li>
I have this chosenAnswer ng-click function in my template.
Here's my controller
appTitan.controller('MainController', ['$scope', '$http', '$location', function($scope, $http, $location) {
'use strict';
//Generate scores
$scope.chosenAnswersArr = [];
}]);
I am unable to push data from directive to the controller. What is that I have to do to make it work.
The error I'm getting is
angular-1.4.8.min.js:107 TypeError: Cannot read property 'push' of undefined
I did try adding the controller property(MainController) to the directive but it was breaking the data. Please note that the data is pulled using the same controller using $http.get(I didn't add that line here). I am mentioning this because to let you know that the data is dynamic.
How can I push a data from my directive to the controller?
I'm a total angular noob and trying to create a simple test app where. I'd like to read out some userdata in a partial. The user data is in my event controller. I assign the event controller to a form in my new.html partial after navigating to #/new via a route controller.
The error I get when trying to loop through the users in my partial is "Error: ngRepeat:iexp Invalid Expression". I can't figure out how to ng-repeat through those users.
Any thoughts?
My index.html:
<div class="container" style="width: 500px; margin: 0 auto;">
<ul class="nav nav-pills" ng-controller="NavigationController as navigationCtrl">
<li ng-class="{active: navigationCtrl.isActive(1)}">
Home
</li>
<li ng-class="{active: navigationCtrl.isActive(2)}">
Nieuw
</li>
<li ng-class="{active: navigationCtrl.isActive(3)}">
Nog een
</li>
</ul>
<div ng-view></div>
</div>
My new.html partial
<form action="" ng-controller="EventController as event">
<div ng-repeat="users as user">
<label>Name</label>
<input type="text" class="form-control" name="name" ng-model="user.name">
<br>
<label>Emailaddress</label>
<input type="email" class="form-control" name="email" ng-model="user.email">
<br>
<input class="btn btn-default" type="submit" ng-click="event.addEvent($event)" value="Klik">
</div>
</form>
And last: My angular code
(function () {
var app = angular.module('testApp', ['ngRoute']);
app.controller('NavigationController', ['$scope', '$route', function ($scope, $route) {
$scope.$route = $route;
this.activeTab = 1;
this.setActiveTab = function (tab) {
this.activeTab = tab;
};
this.isActive = function (tab) {
if ($route.current && $route.current.activeTab) {
return $route.current.activeTab === tab;
}
return false;
};
}]);
app.controller('EventController', ['$scope', '$controller', function ($scope, $controller) {
this.users = [
{name: 'aa'},
{name: 'bb'}
];
this.addEvent = function (e) {
e.preventDefault();
console.log(this);
};
}]);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/new', {
templateUrl: 'partials/new.html',
controller: 'NavigationController',
activeTab: 2
}).
when('/another', {
templateUrl: 'partials/another.html',
controller: 'NavigationController',
activeTab: 3
}).
otherwise({
redirectTo: '/',
controller: 'NavigationController',
activeTab: 1
});
}]);
})();
I've tried changing this for $scope to no avail.
You write ng-repeat in wrong way in your new.html partial page
it should be like
new.html
<div ng-repeat="user in users">
Correct syntax for ng-repeat is
<element ng-repeat="item in [1,2,3]">
Also you can use things like track by $index if you have duplicated values in your collection like [1,1,1].
Ref. https://docs.angularjs.org/api/ng/directive/ngRepeat
There are few issues in your code. Please change all this references to $scope and then quickly fix below html code:
<div ng-repeat="user in users">
It should work but update me otherwise also.
Working demo for your reference (route codes excluded for demo purpose only)
thanks,
Ashok
you have not written ng-repeat in right way change it to:
<div ng-repeat="user in users">
I have been trying to transclude content of an element, and manipulate it's display property by binding click event to one of the children of the element. But it doesn't seem to be working.
app.directive('apple', function(){
function link(scope, elem, attr, ctrl, transclude) {
elem('a.link').bind('click', function() {
('ul.menu').toggleClass('active');
});
transclude(scope, function(clone) {
elem.html(clone);
});
}
return {
restrict: 'E',
transclude: true,
link: link
};
});
HTML:
<apple>
<a class="link" href="#">Show</a>
<ul class="menu">
<li>linky</li>
</ul>
</apple>
Any idea what's going on? link to fiddle: http://jsfiddle.net/pb2q4zj4/1/
Just in case you're really trying to make a drop down menu, rather than working out how transclude works, here's a simpler way;
View
<div ng-app ng-init="show=false">
<div>
<a ng-click="show = !show">Show</a>
<ul ng-show="show">
<li>linky</li>
</ul>
</div>
</div>
JS
angular.module('app', []);
http://jsfiddle.net/4oq1zLsg/
I had strucked in passing value from controller to directive
I have two arrays in my controller
$scope.displayPeople.push(data.userName);
$scope.displayOrg.push(data.orgname);
i need to pass these data from controller to directive
my directive
<div>
<div class="multitext-wrap blue-border">
<ul inputfocus>
<!--<li class="tag" ng-repeat="list in selecteditemsdisplay track by $index" ng-class="{selected: $index==selectedIndex}" >-->
<!--<span class="tag-label">{{list}}</span><span class="tag-cross pointer" ng-click="Delete($index,selecteditemslist[$index],list,searchid)">x</span>-->
<!--</li>-->
<li class="tag" ng-repeat="list in displayItems track by $index" ng-class="{selected: $index==selectedIndex}" >
<span class="tag-label">{{list}}</span><span class="tag-cross pointer" ng-click="Delete($index,selecteditemslist[$index],list,searchid)">x</span>
</li>
<li class="">
<input type="text" ng-model="searchModel" ng-keydown="selected=false" ng-keyup="searchItem(searchModel,searchobj)"/>
</li>
</ul>
</div>
<div class="typeahead" ng-hide="!searchModel.length || selected">
<div class="typeahead" ng-repeat="item in searchData | filter:searchModel | limitTo:8" ng-click="handleSelection(item,searchobj,$index,searchid)" style="cursor:pointer" ng-class="{active:isCurrent($index)}" ng-mouseenter="setCurrent($index)">
<div class="bs-example">
<div class="list-group list-group-item active">
{{item.displayConfig[0].propertyValue}} {{item.displayConfig[1].propertyValue}}
</div>
</div>
</div>
</div>
</div>
I was using $emit to send
in controller
$rootScope.$emit("displayEvent", {displayItems: $scope.displayPeople});
$rootScope.$emit("displayEvent", {displayItems: $scope.displayOrg});
in directive
$rootScope.$on('displayEvent', function (event, args) {
$scope.displayOrgs = args.displayItems;
console.clear();
console.info($scope.displayOrgs);
});
by doing this i getting duplicates in place of org (both people and org wher coming )
how can i solve this problem please hepl me thanks in advance
By declaring 'scope: false' you´re able to access the controller´s scope in your directive. 'false' means 'do not create an isolated scope, inherit the controllers'.
.directive('myDirective', function() {
return {
scope: false,
link: function($scope){
//Do stuff with $scope.displayOrgs
//Do stuff with $scope.displayPeople
}
};
});
This option will create an isolated scope and inherits the selected variables. This is a cleaner way of doing it.
.directive('myDirective', function() {
return {
scope:{
displayPeople:'=',
displayOrg :'=',
},
link: function($scope){
//Do stuff with $scope.displayOrgs
//Do stuff with $scope.displayPeople
}
};
});
using $emit for communication between controller and directive is not a preferable.
you need to use "=" scope of directive to allow two-way communication between controller and directive like:
directive
angular.module('YourModuleName').directive('yourDirectiveName',function () {
return{
restrict:'E',
scope:{
displayPeople:'=',
displayOrg :'=',
},
link: function postLink(scope, element, attrs) {
}
}
});
template respective to controller
<yourDirectiveName displayPeople="displayPeople" displayOrg ="displayOrg "></yourDirectiveName >
I have this directive:
App.directive('typeahead', function($timeout) {
return {
restrict: 'AEC',
scope: {
items: '=',
prompt:'#',
title: '#',
subtitle:'#',
model: '=',
selindex: '=',
onSelect:'&'
},
link:function(scope,elem,attrs){
scope.handleSelection=function(selectedItem){
scope.model=selectedItem;
scope.current=0;
scope.selected=true;
$timeout(function(){
scope.onSelect();
},200);
};
scope.current=0;
scope.selected=true;
scope.isCurrent=function(index){
return scope.current==index;
};
scope.setCurrent=function(index){
scope.current=index;
};
},
templateUrl: 'templates/templateurl.html'
}
});
I have this html:
<typeahead items="items" prompt="Start typing a US state" title="name" subtitle="id" model="name" on-select="onItemSelected()"/>
Directice is using this template:
<input type="text" ng-model="model" placeholder="{{prompt}}" ng-keydown="selected=false"/><br/>
<div class="items" ng-hide="!model.length || selected">
<div class="item" ng-repeat="item in items | filter:model track by $index" ng-click="handleSelection(item[subtitle])" style="cursor:pointer" ng-class="{active:isCurrent($index)}" ng-mouseenter="setCurrent($index)">
<p class="title">{{item[title]}}</p>
<p class="subtitle">{{item[subtitle]}}</p>
</div>
This calls the function in the directive:
scope.handleSelection=function(selectedSubtitle){
What I try to achieve is to call:
handleSelection(item[title], item[subtitle])
And pick it up in the directive like this:
scope.handleSelection=function(selectedTitle, selectedSubtitle){
However, the selectedSubtitle in the directive remains empty. How can I pass the additional parameter to the directive?