I have a situtation where in i want to avoid using $emit to share a scope variable and instead share some property using a underlying service, the problem is that the property value gets set on return of a promise response in directive 1 and by the time that property value is set in service through directive 1, directive 2 is already loaded and hence the property comes as undefined in directive 2.
Any ideas?
With the provided information, thought of writing this code fragment. Hope this will give you some insights to find the best answer.
angular.module('myApp').service('SomeService', function($http) {
this.readData = function(dataUrl) {
// read data;
return $http.get(dataUrl)
.then(function(res) {
return res.data;
}, function(res) {
return res;
}
}
return this;
});
angular.module('myApp').controller('MyController', function($scope, SomeService) {
$scope.readData = function(url) {
SomeService.readData(url)
.then(function(res) {
$scope.data = res;
}, function(res) {
// Display error
}
}
}
angular.module('myApp').directory('myDirectory1', function() {
return {
restrict: 'A',
link: function(scope, elm, attrs) {
scope.data = scope.readData(url);
}
}
});
angular.module('myApp').directory('myDirectory2', function() {
return {
restrict: 'A',
scope: {
data : '#'
},
link: function(scope, elm, attrs) {
scope.$watch('data', function(newVal) {
// Do some stuffs
});
}
}
});
Perhaps extract the functionality that delivers the promise from your directive1 to the service, and in both directives use
.then(function(data){ ... } )
Related
When i run this i get no value at all, just endless looping errors. (Error: [$rootScope:infdig])
My html:
{{getName(5)}}
This is my function:
$scope.getName = function(id) {
$http.get('get.php?id='+id).then(function(response) {
return response.data;
});
}
When i call get.php?id=5 i get a normal answer like: "Jake Something"
When i call $scope.getName(5) in my controller i get the right value, no errors.
Is there a way to fix this or any other way to get the right values?
Fixed it by using directive:
myApp.directive('getCustomer', function($http) {
return {
restrict : 'E',
scope: {
customerid: '='
},
template: "{{data}}",
link: function(scope, elem, attr) {
var url = 'get.php?id='+scope.customerid;
$http.get(url).then(function(response) {
scope.data = response.data;
});
}
};
});
in html:
<get-customer customerid="5"></get-customer>
Outputs:
Jake Something
I am trying to open dialogs, which have their own Controllers, opening them through events.
My problem now is, that I am always getting
Cannot read property $emit of undefined`, because for some reason
my $rootScope is undefined.
How can I inject the $rootScope properly?
I am using Angular 1.6.7.
.directive("opendialog", [function($rootScope) {
return {
link: function(scope, element, attributes) {
element.bind("click", function(event) {
var dialogId = $(element).attr("id");
$rootScope.$emit(dialogId, {
command: "open"
});
});
}
}
}]);
Try this
.directive("opendialog", ["$rootScope", function ($rootScope) {
return {
link: function (scope, element, attributes) {
element.bind("click", function (event) {
var dialogId = $(element).attr("id");
$rootScope.$emit(dialogId, {command: "open"});
});
}
}
}]);
I'm trying to create a directive that is going to go back a page to my search document form and call my 'documentSearch' method. I'm not sure what is going wrong here as browser complains
Uncaught TypeError: Cannot read property 'dsSvc' of undefined
APPCONFIG.dsSvc stores information where the web service is stored. It works absolutely fine from search page but in this directive I'm creating doesn't. Any idea why? I'm stuck on this for long enough. I'm not entirely sure if it's going to work the way I do it (go back a screen and call the web service).
app.directive('previousPage', ['$window', function($window) {
return {
restrict: 'A',
link: function (scope, elem, attrs, $scope,GenericServiceSvc,APPCONFIG) {
elem.bind('click', function () {
$window.history.back();
var paramsBack = JSON.parse(window.localStorage.getItem('srchParams'));
var svcData = {
invoke: 'documentSearch',
app: APPCONFIG.dsSvc,
params: paramsBack
};
GenericServiceSvc.callService(svcData).then(
function (response) {
if (response) {
console.log(response);
} else {
//no results
}
}, function () {
console.log(svcData.invoke + '- Fail');
}
);
});
}
};
}]);
The link function has the following signature:
function link(scope, element, attrs, controller, transcludeFn) {...}
It looks like you're trying to inject APPCONFIG (is it a service/factory/constant?) into the link function, so what you're really asking is for AngularJS to get dsSvc from what it expects to be the transcludeFn argument.
Move your injections to the directive function:
app.directive('previousPage', ['$window', 'GenericServiceSvc', 'APPCONFIG', function($window, GenericServiceSvc, APPCONFIG) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('click', function () {
$window.history.back();
var paramsBack = JSON.parse(window.localStorage.getItem('srchParams'));
var svcData = {
invoke: 'documentSearch',
app: APPCONFIG.dsSvc,
params: paramsBack
};
GenericServiceSvc.callService(svcData).then(
function (response) {
if (response) {
console.log(response);
} else {
//no results
}
}, function () {
console.log(svcData.invoke + '- Fail');
}
);
});
}
};
}]);
My goal is to output a value (from a service) through a element directive so that the html will look like this <msg msg="alertMsg"></msg> and out pops a value from the service.
Here is my code thus far:
app.directive("msg", ['MsgService', function(MsgService) {
return {
restrict: "E",
scope: {//something here to pass MsgService to template },
template: 'Message:{{MsgService.getAlertMsg()}}'
};
}]);
app.service('MsgService', function() {
this.alertMsg = 'default';
this.getAlertMsg = function(){
return this.alertMsg;
};
this.setAlertMsg = function(string) {
this.alertMsg = string;
};
});
HTML would parse/compile to...
<msg msg="alertMsg">Message: default</msg>
What other code do I need?
If a service wont work directly, Should I access it through a controller?
app.directive("msg", function() {
return {
restrict: "E",
scope: {
getMsg: '&msg'
},
controller: 'MsgController',
template:'Message:{{getMsg()}}'
};
}]);
app.controller('MsgController', ['MsgService' , function(MsgService){
this.getAlertMsg = function(){
return MsgService.getAlertMsg();
};
}]);
HTML would parse/compile to...
<msg msg="getAlertMsg()">Message: default</msg>
Sorry for any errors in code or function use, I'm fairly new to Angular.
You can use the link function of the directive. This function is called once for every rendered instance of your directive. It receives, among other things, the scope of your directive. You can extend your scope very easily with the result of calling the MsgSevice.getAlertMsg() service method:
var app = angular.module("app", []);
app.directive("msg", ['MsgService', function(MsgService) {
return {
restrict: "E",
scope: true,
template: 'Message:{{msg}}',
link: function (scope, $element, attrs) {
scope.msg = MsgService.getAlertMsg();
}
};
}]);
app.service('MsgService', function() {
this.alertMsg = 'default';
this.getAlertMsg = function(){
return this.alertMsg;
};
this.setAlertMsg = function(string) {
this.alertMsg = string;
};
});
Later on, I presume you will want to just display the alert message from the msg DOM attribute of the msg directive. Achieving this is much more simple, since AngularJS is already prepared for this common use case. The solution involves creating an isolate scope. The isolate scope can be populated with properties from the parent environment. One possibility is to use the value of a DOM attribute from your directive's element using the "#" syntax. In this case you won't even need the entire MsgService service:
app.directive("msg", function () {
return {
restrict: "E",
scope: {
"msg": "#"
},
template: 'Message:{{msg}}'
};
});
Simplest would be to set the service on your scope and use that in your template:
app.directive("msg", ['MsgService', function(MsgService) {
return {
restrict: "E",
scope: { },
template: 'Message:{{MsgService.getAlertMsg()}}',
link: function(scope, element, attrs) {
scope.MsgService = MsgService;
}
};
}]);
I cannot get the parent function call from the isolated scope..The purpose of this code is to create a widget directive which can be used multiple times on the same page... I tried some other option, but doesn't work either. It works using the parent scope.
What am I missing here.
var app = angular.module("winApp", []);
app.controller("winCtrl", function($scope, dataFactory) {
$scope.getData = function() {
dataFactory.get('accounts.json').then(
function(data) {
$scope.items = data;
});
};
});
app.directive("windowSmall", function() {
return {
restrict : 'EA',
replace : 'true',
scope : {
type : '&'
},
transclude: 'true',
templateUrl : 'windowtemplate.html',
link : function(scope, element, attrs) {
element.bind("load", function(){
console.log(attrs.type);
if (angular.equals(attrs.type, 'getData()')) {
scope.active = 'accounts';
console.log(attrs.type);
// scope.getData();
scope.$apply(function() {
scope.$eval(attrs.type);
});
}
});
}
};
});
app.factory('dataFactory', function($http) {
return {
get : function(url) {
return $http.get(url).then(function(resp) {
return resp.data;
});
}
};
});
HTML:
<div ng-app="winApp" ng-controller="winCtrl">
<window-small type = "getData()"> </window-small>
<br> <br>
<!--
<window-small type = "bulletin"> </window-small> -->
You can also use $rootScope for a full proof solution. Due to the fact that an application can have multiple parents but only one $rootScope.
https://docs.angularjs.org/api/ng/service/$rootScope
Replace your link function with :
link : function(scope, element, attrs) {
element.bind("load", function(){
console.log(attrs.type);
if (angular.equals(attrs.type, 'getData()')) {
scope.active = 'accounts';
console.log(attrs.type);
scope.type();
}
});
}
Fiddle : http://jsfiddle.net/X7Fjm/3/