Directive with js-call in the template - method does not get called - angularjs-directive

In my angular app, I have an alert-service, which handles the list of alerts. I then have a directive, which renders all the alerts to the page. I use the UI Bootstrap components.
However, the close button of the alert does not call the method:
.directive('someAlert', ['alertService', function (alertService){
var templateString = '<uib-alert ng-repeat="alert in vm.alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>';
return {
restrict: 'E',
template: templateString,
scope: true,
controller: function(){
var vm = this;
vm.alerts = alertService.get();
vm.closeAlert = function (index) {
console.log('closeAlert within directive controller called');
alertService.closeAlertIdx(index);
}
},
controllerAs: 'vm',
replace: true
}
}]);

Try this in the templateString
close="vm.closeAlert($index)"

I added a close method directly to the alert-instance. Then the alert.close() is working as expected. Nice solution found: alertservice and a slightly modified

Related

Passing an object to attributes of directive in angularjs

I have a directive which creates a modal.I am trying to pass an object through attributes to this directive.
<modal-dialog model="viewSummaryDialog" info="{{info}}"></modal-dialog>
And I'm retrieving it through attributes like this
return {
restrict: 'E',
scope: {
model: '=',
info:'#',
},
link: function(scope, element, attributes) {
scope.info=scope.$eval(attributes.info);
In my HTML info is an object which has ng-model of different text fields and dropdowns
My problem is that info is not being updated with whatever I enter in the text fields.I am getting only auto selected drop down values in my info object in the directive.I understand this is because link function is being called even before I enter anything in text fields.
Is there any way to make sure that my info object is passed only after I enter all the fields in the form? I am not very clear about how to pass an object to the directive.I tried using resolve function also in my directive but that didn't work.
Thanks in advance :-)
Passing object to directive
var myApp = angular.module('myApp',[]);
myApp.directive('passObject', function() {
return {
restrict: 'E',
scope: { object: '=' },
template: '<div>Hello, {{object.prop}}!</div>'
};
});
myApp.controller('MyCtrl', function ($scope) {
$scope.object = { prop: "world" };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<pass-object object="object"></pass-object>
</div>

Manipulating expressions in AngularJS

I want to be able to achieve a functionality similar to the following:
HTML
<mydir> {{config = {type: 'X', options: 'y'}} </mydir>
<mydir> {{config = {type: 'a', options: 'b'}} </mydir>
JS Directive
angular
.module('mymod', ['dependency'])
.controller('myCtrl', function($scope){
this.config = config;
this.type = config.type;
this.options = config.options
});
.directive('mydir', function($compile, $window){
return{
... code
template:
`<textarea type=this.type options=this.options> </textarea>
}
});
The goal would be to be able to pass a variety of configurations through, to the controller and let the directive take care of the templating. So that way I can pass whatever combinations of configurations through and the directive should handle it.
Not sure if it's possible to achieve this in Angular since I just got into it but hopefully it isn't too complicated.
If your goal is to pass a configuration parameter to your directive you can do it through the isolated scope of your directive. So that you can pass whatever configuration you like to your directive to handle it.
The following snippet implements this solution.
angular
.module('mymod', ['dependency'])
.controller('myCtrl', function($scope) {
this.config = {
type: 'a',
options: 'b'
};
})
.directive('mydir', function($compile, $window) {
return {
scope: {
config: '='
},
template: `
<textarea type="{{ config.type }}" options="{{ config.options }}">
</textarea>
`
}
});
<mydir config="{type: 'X', options: 'y'}"></mydir>
<mydir config="$ctrl.config"></mydir>

access app controller scope inside custom directive in ng-repeat

I'm new to this so sorry if I'm asking something obvious. I have an app with controller holding some config variables in scope. I have a custom directive used inside ng-repeat that will have to make use of this config. For debugging purposes I need the changes to config bee reflected inside the directive. How can I achieve this.What I have so far is not working my pointsmap is undefined
angular.module('demo', [])
.directive('demoDir', function () {
var dirController = ['$scope', function ($scope) {
$scope.totalPoints = 0;
$scope.$watch('person', function(newVal, oldVal){
resetPoints(newVal);
}, true);
function resetPoints(pPerson){
$scope.totalPoints = $pointsMap['VIP'] * pPerson.points ;
}
return {
restrict: 'E',
scope: {
person: '=' ,
pointsMap : '='
},
controller: dirController,
template: '<span> {{totalPoints}}</span>'
}
})
.controller('mainAppController', function ($compile, $scope, $q ) {
/*CONFIG */
$scope.points = {
'VIP': 8.50,
'Standard': 7.50,
};
});
<demoDir person='myobject' pointsMap='points' />
Any particular reason why you want your directive to have isolated scope? If there is no restriction to use isolated scope, you can simply make the scope of the directive as false(now directive will use parent scope)
angular.module('demo', [])
.directive('demoDir', function () {
var dirController = ['$scope', function ($scope) {
$scope.totalPoints = 0;
$scope.$watch('person', function(newVal, oldVal){
resetPoints(newVal);
}, true);
function resetPoints(pPerson){
$scope.totalPoints = $pointsMap['VIP'] * pPerson.points ;
}
return {
restrict: 'E',
scope: false,
controller: dirController,
link: function(scope, element, attrs){
//scope.points should be available
}
template: '<span> {{totalPoints}}</span>'
}
})
.controller('mainAppController', function ($compile, $scope, $q ) {
/*CONFIG */
$scope.points = {
'VIP': 8.50,
'Standard': 7.50,
};
});
//assuming that your directive is housed inside the mainAppController
<div ng-controller="mainAppController">
<demoDir/>
</div>
You will also have access to the parent scope properties in the directive's link function if you want to use.

Set angular directive attribute by calling function

I'm trying to set the value of a directive's attribute by calling a function on the containing page's controller, but it doesn't work as expected. In the code below, the "make" object does not have a "modelList" property, so I must place a separate call to the server to get it for each make.
<div ng-repeat="make in makeList">
<model-list-directive model-list="getModelList(make)" />
</div>
app.controller("myController",function($scope) {
$scope.getModelList = function(make) {
return null;
//return myService.getModelList(make);
};
})
app.directive("modelListDirective",function() {
restrict:'E',
scope: {
modelList: '='
},
template: '<ul><li ng-repeat="model in modelList">{{model.modelName}}</li></ul>',
controller: ['$scope', function ($scope) {
}]
If the getModelList() function is set to return null (not commented out in the code), no error is given, but the function is called multiple times (randomly varies between 3 and 5 usually).
The real problem comes when I invoke myService.getModelList(make) (commented out in the code). This results in an endless loop of calls to the service, which crashes the browser.
I'm guessing this is because of two-way binding, but I'm not sure.
Is there a better way to get dynamic data to the directive?
I think part of the problem is that your directive definition isn't returning an object. It should look like this:
app.directive('modelListDirective',function() {
return { // <-- need to return an object
restrict:'E',
scope: {
modelList: '='
},
template: '<ul><li ng-repeat="model in modelList">{{model.modelName}}</li></ul>',
controller: ['$scope', function ($scope) {
}]
};
});
However, you're passing a function as a 2-way binding into the directive, which you shouldn't do. See this answer to a similar issue.
What you can do instead is inject myService directly into your directive, then have your directive call myService.getModelList() in its link function.
So your markup would look like this:
<div ng-repeat="make in makeList">
<model-list-directive make="{{make}}" />
</div>
Each directive instance would just need the make.
And your directive definition would look like this:
app.directive('modelListDirective', ['myService', function(myService) {
return {
restrict:'E',
scope: {
make: '#'
},
link: function (scope, element, attrs) {
scope.modelList = myService.getModelList(scope.make);
},
template: '<ul><li ng-repeat="model in modelList">{{model.modelName}}</li></ul>',
controller: ['$scope', function ($scope) {
}]
};
}]);
setting scope.modelList in its link function.
Here's a fiddle.

How to use a angularjs route to call a javascript function

I'm trying to use the routing of angularjs to call a javascript function if a certain url is used.
The following code is not providing the expected result:
var app = angular.module('myApp', []);
app.config(function($routeProvider) {
$routeProvider.when('/link1', {
controller: 'PageController'
})
.when('/link2', {
controller: 'PageController'
})
.otherwise({
controller: 'PageController'
});
});
app.controller('PageController', function($scope, $routeParams) {
alert('1');
});
The alert(1); is not called if one of these URLs are requested...
Maybe someone knows how to solve this ?
Controller is not called until you specify template or templateUrl option in $routeProvider configuration. If there is no template needed, you could specify one-space char (but not empty string). Like so
$routeProvider.when('/link1', {
controller: 'PageController',
template: ' '
})
There is no way to associate the routing with a specific action in the controller. The routing in the AngularJS is not like the routing in other web frameworks to route to specific action of request. Instead, the routing in the AngularJS is primarily relating to handle the page flow and the controller defines the scope of the page.
However, if you put the alert in the controller like that, it should be triggered when the page is loaded. You need to check whether the URL you used is correct or not. To test, you can simply put $location.url('/link1') in your code.
If your controller is being used on a particular route, then you can call that function inside the controller. It will get executed once the route changes and your controller is called.
In this http://plnkr.co/edit/qUZ5Q7nKCRAS8dFvjRIg when you click on link1 it displays alert.
I can't quite catch why your code doesn't work as expected, but I created a similar app setup and it works:
var app = angular.module('myApp',[]).
config(['$routeProvider',function($routeProvider) {
$routeProvider.
when('/', {
controller: 'PageController',
template: '<br><br>this is page #/<br> {{data}}',
}).
when('/link1', {
controller: 'SpecificPageController',
template: '<br><br>this is page #/link1<br> {{data}}'
}).
when('/link2', {
controller: 'PageController',
template: '<br><br>this is page #/link2<br> {{data}}'
}).
otherwise({redirectTo:'/'});
}]).
controller('PageController', function($scope, $routeParams) {
$scope.data = 'hello world';
}).
controller('SpecificPageController', function($scope, $routeParams) {
$scope.data = 'hello specific';
alert(1);
});
Whenever SpecificPageController is assigned to a route, and that route opened, the alert function gets executed.