How pass variables to directive from controller? - javascript

HTML:
<div ng-repeat="item in productArr">
{{ item.title }}
</div>
<div category-page-navigation current-page='currentPage' category-products-count='productsCount'></div>
JS:
.controller('categoryController', ['$scope', '$location', '$http', '$q', '$window', '$stateParams', function($scope, $location, $http, $q, $window, $stateParams) {
$scope.currentPage = 1;
$scope.productsCount = 0;
var GET = {
getProductData: function() {
var defer = $q.defer();
$http.post('services/loadProduct.php', {
'id' :1,
}).then(function(response) {
defer.resolve(response);
}, function(response) {
defer.resolve([]);
});
return defer.promise;
}
};
var getData = {
getProduct: function() {
var productData = GET.getProductData();
$q.all([productData]).then(
function(response) {
$scope.productArr = response[0].data.products;
$scope.productsCount = response[0].data.products.length;
});
}
};
getData.getProduct();
}])
.directive('categoryPageNavigation', function($compile, $parse) {
return {
scope: {
currentPage: '=currentPage',
categoryProductsCount: '=categoryProductsCount'
},
link: function (scope, element, attrs) {
debugger;
// Here scope.categoryProductsCount = undefined
// ...
$scope.$watch(scope.currentPage, function(value) {
// ...
});
}
};
});
I try to form new HTML for navigation to manipulate with HTML I get from ng-repeat.
In directive I need currentPage(from start =1) and total count of items from ng-repeat(length of array) witch I get from service. How I can pass variables to directive? First I need to get variables from service(ajax request or something else) then pass variables(some ather data) to directive.

If I understood correctly what you mean. Here is a code pen example on how to shared data between you controller and your directive.
A good read to understand the code below:https://docs.angularjs.org/guide/providers
http://codepen.io/chocobowings/full/Xmzxmo/
var app = angular.module('app', []);
//-------------------------------------------------------//
app.factory('Shared', function() {
return {
sharedValue: {
value: '',
}
};
});
//-------------------------------------------------------//
app.controller('ctrl', function($scope, Shared) {
$scope.model = Shared.sharedValue;
});
//-------------------------------------------------------//
app.directive('directive', ['Shared',
function(Shared) {
return {
restrict: 'E',
link: function(scope) {
scope.model = Shared.sharedValue;
},
template: '<div><input type="text" ng-model="model.value"/></div>'
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
Ctrl:
<div ng-controller="ctrl">
<input type="text" ng-model="model.value" />
<br/>
</div>
Directive:
<directive value="model.value"></directive>
</div>

Related

injecting service into directive returns undefined

I am injecting a serivce into a directive and for some instance this service returns undefined can anyone explain what I am doing wrong?
Here is a plunker of the code below. https://plnkr.co/edit/H2x2z8ZW083NndFhiBvF?p=preview
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.players = ["A","B","C"];
});
app.factory('PlayerListS', [function() {
var playerList = [];
function getList() {
return playerList;
}
function addToList(name) {
playerList.push(name);
}
return {
addToList :addToList,
getList: getList
}
}]);
app.directive("player",['PlayerListS', function (PlayerListS) {
return {
restrict: 'E',
scope: {
person:'#person',
add:'&add'
},
replace: false,
templateUrl: "player.html",
controller: function($scope, $element, $compile) {
$scope.add = function(name) {
PlayerListS.addToList(name);
console.log(PlayListS.getList());
}
}
};
}]);
You have a typo in your console because of which the code is throwing an error. Change your directive the following way
app.directive("player",['PlayerListS', function (PlayerListS) {
return {
restrict: 'E',
scope: {
person:'#person',
add:'&add'
},
replace: false,
templateUrl: "player.html",
controller: function($scope, $element, $compile) {
$scope.add = function(name) {
debugger;
PlayerListS.addToList(name);
console.log(PlayerListS.getList());
}
}
};
}]);
Working Demo: https://plnkr.co/edit/HhmOYyoZAhm6vvXp3puC?p=preview

AngularJS view doesn't update when ng-model value changed

Please check this codepen, when clicked on the button click me to reset name, the name input should be reset to empty, when I do console.log on the directive scope, I do see name is set to empty string, but the value in the view not get updated. What's wrong?
CodePen example
angular.module('mainApp', [])
.directive('myTab', function() {
return {
restrict: 'E',
template: 'name: <input type="text" ng-model="name">',
controller: function($location, $scope) {
$scope.name = 'myname';
$('#clickMeToReset').on('click', function() {
$scope.name = '';
})
}
};
})
.directive('myMenu', function() {
return {
restrict: 'E',
template: '<button id="clickMeToReset">click me to reset name</button>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="mainApp">
<my-menu></my-menu>
<my-tab></my-tab>
</div>
After
$scope.name = '';
Do a
$scope.$apply();
When you use other libraries like jquery in angular, changes to variables like
$scope should manually broadcast.
$('#clickMeToReset').on('click', function(){
$scope.name = '';
$scope.$apply();
})
so $scope.$apply(); will do the trick!
Modify your controller code with the following:
controller: function($location,$scope, $timeout){
$scope.name = 'myname';
$('#clickMeToReset').on('click', function(){
$timeout(function() {
$scope.name = '';
});
})
}
angular.module('mainApp', [])
.directive('myTab', function() {
return {
restrict: 'E',
template: 'name: <input type="text" ng-model="name">',
controller: function($location, $scope, $timeout) {
$scope.name = 'myname';
$('#clickMeToReset').on('click', function() {
$timeout(function() {
$scope.name = '';
});
})
}
};
})
.directive('myMenu', function() {
return {
restrict: 'E',
template: '<button id="clickMeToReset">click me to reset name</button>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="mainApp">
<my-menu></my-menu>
<my-tab></my-tab>
</div>
Since you are using jQuery to change the value, which is out of the Angular's context, so Angular is unaware of the change. So you need to tell Angular that something has changed. So we are using $timeout service to achieve this. We can also use $scope.$apply() but that may fail when the digest cycle is already in progress.
Important
You should use ng-click instead and remove dependency of jQuery if possible since jQuery is also a big library in itself like Angular (see a working example below):
angular.module('mainApp', [])
.directive('myTab', function() {
return {
restrict: 'E',
template: 'name: <input type="text" ng-model="name">',
controller: function($scope) {
$scope.name = 'myname';
$scope.clearName = function() {
$scope.name = '';
}
}
};
})
.directive('myMenu', function() {
return {
restrict: 'E',
template: '<button ng-click="clearName()">click me to reset name</button>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="mainApp">
<my-menu></my-menu>
<my-tab></my-tab>
</div>
I hope According to my thinking this code help you . Only change Js code remaining HTML code is proper.
var mainApp = angular.module('mainApp', []);
mainApp.directive('myTab', function() {
return {
template: 'name: <input type="text" ng-model="name">',
controller: function($location,$scope){ debugger;
$scope.name = 'myname';
$('#clickMeToReset').on('click', function(){
$scope.name = '';
})
}
};
})
.directive('myMenu', function() {
return {
name:"clickMeReset",
template: '<button id="name" ng-click="clear()">click me to reset name</button>',
controller:
function($location,$scope){
$('#name').on('click', function(){
$scope.name = '';
})
}
};
});

AngularJS expected information not displaying

I am working on a mobile application that gets a list of jobs from the server (WEBAPI) and populates the proper fields. When the user clicks on the job name, the application goes to a details page, where the job information needs to show again.
I am having issues getting the information to show.
Here is the index:
.state('jobs',{
abstract: true,
url: '/jobs',
templateUrl: 'modules/jobs/views/jobs.html',
controller: ['$scope', '$state', '$stateParams', 'jobs', function($scope, $state, $stateParams, jobs) {
jobs.getData()
.then(function(jobs) {
$scope.jobs = jobs;
});
}]
})
// Jobs > List
.state('jobs.list', {
url: '',
title: 'All Jobs',
templateUrl: 'modules/jobs/views/jobs.list.html'
})
// Jobs > Detail
.state('jobs.detail', {
url: '/{JobId:[0-9]{1,4}}',
title: 'Job Details',
views: {
'details': {
templateUrl: 'modules/jobs/views/jobs.detail.html',
controller: ['$scope', '$state', '$stateParams', 'utils', function($scope, $state, $stateParams, utils) {
$scope.job = utils.findById($scope.jobs, $stateParams.JobId);
$scope.edit = function(){
$state.go('.edit', $stateParams);
};
}]
},
'': {
templateUrl: 'modules/jobs/views/jobs.materials.html',
controller: ['$scope', 'materials', '$stateParams', function($scope, materials, $stateParams) {
materials.getDataById($stateParams.JobId)
.then(function(materials) {
$scope.materials = materials;
});
$scope.subHeader = 'Bulk Sack Materials';
}]
}
}
})
Here is the Service:
app.factory('jobs', ['$resource', '$q', '$http', 'localStorageService', function($resource, $q, $http, localStorageService) {
localStorageService.set('SessionId', 'A00DB328-7F9C-4517-AD5D-8EAA16FBBC8F');
var SessionId = localStorageService.get('SessionId');
return {
getData: function() {
var deferred = $q.defer();
$http.get(baseUrl + 'Job/GetJobs?SessionId=' + SessionId, {
cache: true
}).success(function(jobs) {
deferred.resolve(jobs);
});
return deferred.promise;
}
};
}]);
app.factory('materials', ['$resource', '$q', '$http', 'localStorageService', function($resource, $q, $http, localStorageService) {
var SessionId = localStorageService.get('SessionId');
return {
getDataById: function(id) {
var deferred = $q.defer();
$http.get(baseUrl + 'Material/GetMaterials/' + id + '?SessionId=' + SessionId, {
cached: 'true'
}).success(function(materials) {
deferred.resolve(materials);
});
return deferred.promise;
}
};
}]);
And here is the utils service:
app.factory('utils', function() {
return {
findById: function findById(a, id) {
for (var i = 0; i < a.length; i++) {
if(a[i].id === id) {
return a[i];
}
}
return null;
}
};
});
Here is the HTML for the job.list:
<div class="list-group">
<a class="list-group-item" ng-repeat="job in jobs" ui-sref="jobs.detail({ JobId: job.JobId })">
<dl>
<dt>{{job.Name}}</dt>
<dd>{{job.Location}}</dd>
</dl>
Some insight on how to get this to work would be awesome.
Thank You-
If I have inferred your goal correctly, you're issue is on the following line:
$scope.job = utils.findById($scope.jobs, $stateParams.JobId);
$scope.jobs will not exist like you expect it to. The jobs object was created in the list view's controller's scope, not the details view's controller. You'll want to do something like you have in the '' controller
JobService.getJobById($stateParams.JobId).then(function(data) {
$scope.job = data;
});

Bind a service variable to a directive?

I have a controller which contains a function that gets some data from the server. I store that data in a service variable. This service is then injected into a directive. I want the directive to be auto updated, whenever this function is called and the data is renewed.
My controller:
angular
.module('myApp')
.controller('myCtrl', ['$scope', 'SomeService', function($scope, SomeService) {
$scope.update = function() {
SomeService.myValue = 100;
}
}]);
The directive:
angular.module('myApp')
.directive('myDirective', ['SomeService', function(SomeService) {
return {
templateUrl : 'views/myDirective.html',
restrict : 'E',
scope : false,
controller : function($scope) {
this.myValue = SomeService.myValue;
}
};
}]);
The template:
<div>
{{ myValue }}
</div>
The update function is called when a button is clicked and it updates myValue to a new value. I want it to be automatically reflected in the directive.
Plunk: http://plnkr.co/edit/OUPzT4MFS32OenRIO9q4?p=preview
Please see working demo below
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, SomeService) {
$scope.name = SomeService.data;
$scope.update = function() {
$scope.name.myValue += 1;
}
});
app.factory('SomeService', function() {
var data = {
myValue: 0
};
return {
data: data
}
});
app.directive('myDirective', ['SomeService',
function(SomeService) {
return {
templateUrl: 'myDirective.html',
restrict: 'EA',
scope: false,
link: function(scope, elem, attr) {
scope.data = SomeService.data
}
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="MainCtrl">
<p>My Value: {{name.myValue}}</p>
<button ng-click="update()">Click</button>
<hr/>
<div my-directive></div>
<script type="text/ng-template" id="myDirective.html">
<h3>My Directive</h3>
<p>Value: {{data.myValue}}</p>
</script>
</div>
</div>
You can try by adding the reference of the service to the directive itself..
The directive:
angular.module('myApp')
.directive('myDirective', ['SomeService', function(SomeService) {
return {
templateUrl : 'views/myDirective.html',
restrict : 'E',
scope : false,
controller : function($scope) {
this.SomeService = SomeService;
}
};
}]);
The template:
<div>
{{ SomeService.myValue }}
</div>
Edit : I went through your plunker, and have finally got it working.
You can check the updated code here
#RutwickGangurde and others who were having issues, if you're trying to set a scope variable that is not an object it won't work. I'm guessing that's what you're currently doing in your service:
...
this.myVar = true;
...
and then trying to set it in the directive/controller:
...
scope.myVar = myService.myVar;
...
That will NOT work for getting the updated variable in the service when it changes.
Try this instead in your service:
...
this.myObj = {};
this.myObj.myVar = true;
...
and in your directive/controller:
...
scope.myValue = myService.myObj;
...
and in your html:
...
{{ myValue.myVar }}
...
I would have made this as a comment, but I don't have sufficient privileges yet so decided to post as a response with a very brief example.

Using a promise for retrieving data inside angular directive

I am working on hiding or showing elements based on user role from an api. The directive works when I set the data.roleName in the code but when I try to set it by I service I need to resolve a promise before loading the rest of the directive though I keep getting "cannot read property of undefined errors Here's the code.
.js
app.directive('restrictTo', ['SecuritySvc', function (SecuritySvc) {
return {
restrict: 'EA',
replace: true,
transclude: true,
scope: {},
controller: ['$scope', '$attrs', '$q', 'SecuritySvc', function ($scope, $attrs, $q, SecuritySvc) {
var defer = $q.defer();
defer.promise.then(function ($scope, SecuritySvc) {
$scope.data = SecuritySvc.getRole();
});
defer.resolve();
if ($scope.data.roleName == $attrs.restrictTo) {
$scope.allowed = true;
} else {
$scope.allowed = false;
}
console.log($scope.data);
}],
template: '<div ng-show="{{ $scope.allowed }}" ng-transclude></div>'
}
}]);
.html
<div restrict-to="customer">
<div class="hero-unit">
<h1>Welcome!</h1>
<p>Hello, valued customer</p>
</div>
</div>
<div restrict-to="Admin">
<div class="hero-unit">
<h1>Admin Tools</h1>
<p>This shouldn't be visible right now</p>
</div>
</div>
If you dont want to use Q/defer and are using $resource you can do it this way:
app.directive('restrictTo', ['SecuritySvc', function (SecuritySvc) {
return {
restrict: 'AE',
replace: true,
transclude: true,
scope: {},
controller: ['$scope', '$attrs', 'SecuritySvc', function ($scope, $attrs, SecuritySvc) {
$scope.allowed = false;
SecuritySvc.getMyRole().$promise.then(function (data,attrs) {
if (data.roleName == $attrs.restrictTo) {
$scope.allowed = true;
} else {
$scope.allowed = false;
}
});
}],
template: '<div ng-show="allowed" ng-transclude></div>'
};
}]);
Not sure what your SecuritySvc is or returns. I think you should do it in a way like this:
var defer = $q.defer();
defer.resolve(SecuritySvc.getRole());
defer.promise.then(function (data) {
$scope.data = data;
if ($scope.data.roleName == $attrs.restrictTo) {
$scope.allowed = true;
} else {
$scope.allowed = false;
}
console.log($scope.data);
});

Categories

Resources