Angular directive not rendering scope values in view - angularjs

My directive uses a service which returns a promise, I need to display the scope attributes geoZip, geoCity and geoState in the template.
The issue is that those scope variables are not being shown in the template, I just see the comma.
What should I do to make it display the scope variables?
This is my directive code:
.directive('cityStateZip', function() {
return {
restrict: 'A',
transclude: true,
scope: {
zip: '=',
},
template: '<p>{{geoCity}}, {{geoState}} {{geoZip}}</p>',
controller: ['$scope', 'GeolocationService', function ($scope, GeolocationService) {
GeolocationService.geocode($scope.zip).then(function(result) {
if (result) {
console.log(result);
$scope.geoZip = result['address_components'][0]['long_name'];
$scope.geoCity = result['address_components'][1]['long_name'];
$scope.geoState = result['address_components'][2]['short_name'];
}
});
}]
};
})
.service('GeolocationService', ['underscore', '$q', function (underscore, $q) {
var gs = {};
gs.geocode = function(address) {
var geocoder = new google.maps.Geocoder();
var deferred = $q.defer();
geocoder.geocode( { "address": address }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
return deferred.resolve(underscore.first(results));
}
return deferred.reject();
});
return deferred.promise;
}
return gs;
}]);

I found that I have to use the $timeout service to make it work:
.directive('cityStateZip', function() {
return {
restrict: 'A',
transclude: true,
scope: {
zip: '=',
},
template: '<p>{{geoCity}}, {{geoState}} {{geoZip}}</p>',
controller: ['$scope', '$timeout', 'GeolocationService', function ($scope, $timeout, GeolocationService) {
GeolocationService.geocode($scope.zip).then(function(result) {
if (result) {
console.log(result);
$timeout(function() {
$scope.geoZip = result['address_components'][0]['long_name'];
$scope.geoCity = result['address_components'][1]['long_name'];
$scope.geoState = result['address_components'][2]['short_name'];
});
}
});
}]
};
})
Please let me know if there is best alternative (not using $timeout), Thanks!

Related

AngularJS Directive data binding not happening from controller

I am facing the problem of data binding from controller to directive because of delay in response from the server.
To better understand just see a small program below.When I remove the timeout function, binding happens.
<msg track="{{customer}}"></msg>
angular.module('myApp').directive('msg', function() {
return {
scope: {
track :"#"
},
link : function(scope, element, attrs) {
},
template : "<a href>{{track}}</a>"
}
});
angular.module('myApp').controller('HomeCtrl', ['$scope', function($scope) {
setTimeout(function() {
$scope.customer = "shreyansh";
}, 5000);
// assume some service call inside controller
// service1.getData().then(function(data){$scope.customer = data})
}]);
How can i fix above problem so that above code should render as
<msg track="shreyansh" class="ng-isolate-scope">shreyansh</msg>.
Any help is appreciated.
Thanks
var app = angular.module('plunker', []);
app.factory('myService', function($http) {
var promise;
var myService = {
getData: function() {
if (!promise) {
promise = $http.get('test.json').then(function(response) {
return response.data;
});
}
return promise;
}
};
return myService;
});
app.controller('MainCtrl', function(myService, $scope) {
myService.getData().then(function(d) {
$scope.data = d;
});
});
app.directive('msg', function() {
return {
restrict: 'E',
scope: {
track: "#"
},
link: function(scope, element, attrs) {
},
template: "<a href>{{track}}</a>"
}
});
<msg track="{{data.name}}"></msg>
test.json file
{
"name": "Pete"
}

I have a angular directive for kendo grid. My issue is ajax in my service fires only after the complete directive executes

My ajax fires after the complete directive executes. Is there any work around for this so that I can have my grid configuration loads before coming to the grid directive
gridApp.directive('grid', function () {
return {
restrict: "EA",
scope: {
gridName: "#"
},
template: '<h1>kendoDirective</h1><br/><div kendo-grid={{gridName}} options="gridOptions"></div>',
controller: function ($scope, $element, $attrs, widgetUtils) {
var gridConfig = widgetUtils.GetGridOption().then(onLoad);
var onLoad = function (data) {
$scope.gridOptions = data;
}
console.log('DirectiveScope: ' + $scope.gridOptions);
},
link: function ($scope, $element, $attrs) {
}
};
});
gridApp.service('widgetUtils', function ($http) {
var getGridOption = function () {
return $http.get('/Base/LoadGridConfiguration').then(function (response) {
return response.data;
});
}
return {
GetGridOption: getGridOption
};
});
You can handle it with ng-if in template. I created $scope.isReady and change it state after options loaded.
gridApp.directive('grid', function () {
return {
restrict: "EA",
scope: {
gridName: "#"
},
template: '<h1>kendoDirective</h1><br/><div data-ng-if="isReady" kendo-grid={{gridName}} options="gridOptions"></div>',
controller: function ($scope, $element, $attrs, widgetUtils) {
var gridConfig = widgetUtils.GetGridOption().then(onLoad);
$scope.isReady = false;
var onLoad = function (data) {
$scope.gridOptions = data;
$scope.isReady = true; // here we ready to init kendo component
$scope.$apply();
}
console.log('DirectiveScope: ' + $scope.gridOptions);
},
link: function ($scope, $element, $attrs) {
}
};
});

Unit Testing a watch method call in Directive link function

I have the following Directive
.directive("myContainer", function (myContainerService,$window) {
return {
restrict: 'A',
templateUrl: "myContainer/MyContainer.tpl.html",
controller: 'myCtrl',
controllerAs: 'myCtrl',
scope: {
items: '='
},
link: function (scope, element) {
var timeout;
scope.$watch('myCtrl.items', function (items) {
var windowWidth = $window.innerWidth - 65;
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
myContainerService.saveItems(items);
}, 1000);
}, true);
}
};
})
And here is the Unit Test i have.
describe("myCtrl", function(){
var myCtrl;
var dirEle ;
var myScope;
// var to store the Mock Items
var myContainerService = $injector.get('myContainerService');
var items = [..]
beforeEach(inject(function($compile, $httpBackend){
$httpBackend.whenGET(/.*my-app\/restful-services\/items*./).respond({...});
scope.items = myContainerService.getItems();
dirEle = $compile('<div my-container items="items"></div>')(scope);
scope.$digest();
myScope = dirEle.isolateScope();
myCtrl = myScope.myCtrl;
}));
fit("Saving Items", inject(function($timeout){
spyOn(myContainerService, 'saveItems');
//$timeout.flush();
myScope.$digest();
$timeout.flush();
expect(myContainerService.saveItems).toHaveBeenCalledWith(myCtrl.items);
}));
});
And my test is failing as the saveItems is not getting called at all. Not sure what i am doing wrong.
Appreciate any inputs.
Thanks
You need to be using angulars $timeout that way in your test your $timeout.flush() will work:
.directive("myContainer", function (myContainerService,$window, $timeout) {
return {
restrict: 'A',
templateUrl: "myContainer/MyContainer.tpl.html",
controller: 'myCtrl',
controllerAs: 'myCtrl',
scope: {
items: '='
},
link: function (scope, element) {
var timeout;
scope.$watch('myCtrl.items', function (items) {
var windowWidth = $window.innerWidth - 65;
$timeout.cancel(timeout);
timeout = $timeout(function () {
myContainerService.saveItems(items);
}, 1000);
}, true);
}
};
})

How to make function to be fired when directive loaded?

I define this directive:
(function () {
"use strict";
angular.module("inspectionReview").directive("inspectionsReviewsList", ["config",inspectionsReviewsList]);
function inspectionsReviewsList(config) {
var directive = {
restrict: "E",
scope: {
objectId: "=",
region: "="
},
templateUrl: config.baseUrl + "app/InspectionReview/templates/inspectionsReviewsList.templ.html",
controller: "inspectionsReviewsListController",
controllerAs: "list"
}
return directive;
}
angular.module("inspectionReview").controller("inspectionsReviewsListController", ["$scope",
"$uibModal",
"inspectionReviewServices",
"toaster",
inspectionsReviewsListController]);
function inspectionsReviewsListController($scope, $uibModal, inspectionReviewServices, toaster) {
//===============================check status of site object================================
$scope.$watch('inspectionReviews', function () {
_.each($scope.inspectionReviews, function (value, key) {
if (!value.IsNormal) {
return $scope.status = false;
}
$scope.status = true;
})
}, true)
//===================================modal window============================================
$scope.open = function (size) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'app/siteObjects/templates/myModalContent.tmpl.html',
controller: 'myModalWindowController',
size: 'sm',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
//$log.info('Modal dismissed at: ' + new Date());
});
};
}
})();
In the view:
<inspections-reviews-list id="object.Id"></inspections-reviews-list>
How can I make this function:
inspectionReviewServices.getValues(objectId).then(function (result) {
$scope.inspectionReviews = result.data;
});
to be fired when when directive is loaded.
You can assign a function to the directive's link property, as follows:
link : getValues;
The getValues functions is like this:
function getValues(scope, element, attributes) {
inspectionReviewServices.getValues(attributes.id).then(function (result) {
scope.inspectionReviews = result.data;
});
}
use like this... it will work..
function () {
angular.module("inspectionReview").directive("inspectionsReviewsList", ["config",inspectionsReviewsList]);
function inspectionsReviewsList(config) {
var directive = {
restrict: "E",
scope: {
objectId: "=",
region: "="
},
link : function getValues(scope, element, attributes) {
inspectionReviewServices.getValues(attributes.id).then(function (result) {
scope.inspectionReviews = result.data;
});
},
templateUrl: config.baseUrl + "app/InspectionReview/templates/inspectionsReviewsList.templ.html",
controller: "inspectionsReviewsListController",
controllerAs: "list"
}
return directive;
}

Inject service into directive

Cant inject the comment service into comment directive getting errorComment service not found
// Code goes here
var noBlogApp = angular.module("noBlogApp", ['ngRoute', 'ngSanitize', 'commentSystem']);
noBlogApp.config(['routeProvider', function(routeProvider) {
routeProvider.null when('/', {
controller: "noBlogController", null templateUrl: 'post.html',
}).when('/post/:id', {
controller: 'singlePostController',
templateUrl: 'singlepost.html',
});
}]);
noBlogApp.service('commentService', ['http', function(http) {
http.get('js/assureBlog.JSON').success(function(data) {
this.getComment = function(id) {
scope.comment = data[id];
return scope.comment;
}
var addComment = function() {
}
var addReply = function() {
}
var deleteComment = function() {
}
var deleteReply = function() {
}
});
}]);
noBlogApp.controller('noBlogController', ['scope', 'http', function(scope, http) {
scope.message = "hello";
http.get('js/assureBlog.JSON').success(function(data) {
scope.post = data;
});
}]);
nullnoBlogApp.controller('singlePostController', ['scope', 'http', 'routeParams', 'commentService', function(scope, http, routeParams, commentService) {
null http.get('js/assureBlog.JSON').success(function(data) {
scope.post = data[routeParams.id];
});
scope.commentService = commentService;
console.log("this is the" + commentService) null
}]);
noBlogApp.directive('comments', ["commentService", function(commentService) {
return {
scope: {
id: '#'
},
template: id: {
{
id
}
}
link: function(scope, element, attrs, commentService) {
console.log(scope.commentService);
}
};
}]);
Although the question is poorly formatted, it looks like your issue is this:
link:function(scope,element,attrs,commentService)
Remove the commentService from the link function. You've already added the dependency to the directive construction.

Resources