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
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"
}
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) {
}
};
});
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);
}
};
})
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;
}
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.