Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
147
rated 0 times [  151] [ 4]  / answers: 1 / hits: 20925  / 11 Years ago, wed, january 15, 2014, 12:00:00

I moved the following HTML from a controller to a directive, as part of HTML I wanted subbed in when a button was clicked. The problem is that now the save button(below) does nothing. I tried changing the ng-click to a different function I included in the directive code, and that worked, but I know that a function that is saving data belongs in the controller. How can I access the saveStudent function? (When the HTML was right in the view, I used to use $scope.saveStudent in the controller.)



I'm sorry if this question has been asked before. I tried my best to look through the related questions, but I'm new to angular so it's likely I missed a similar one. Thanks!



<button class=btn-bl btn-bl-red pull-right ng-click=saveStudent(addStudentForm); ng-enable=addStudentForm.$valid>
SAVE
</button>


This is the function (within the link function in the directive) that loads the new template when a button is clicked.



        function studentEditForm(element) {
var templateUrl = baseUrl + 'settings-edit.html';
templateLoader = $http.get(templateUrl, {
cache : $templateCache
}).success(function(html) {
element.html(html);
}).then(function() {
var compiled = $compile(element.html())(scope);
element.html(compiled);
});

};

templateLoader.then(function() {
var compiled = $compile(element.html())(scope);
element.html(compiled);
});


I'm wondering if maybe the fact that the HTML is being compiled by the directive is the problem?


More From » html

 Answers
12

m59 isn't wrong.



But sometimes, the real answers aren't that easy (for a thousand different reasons).



There are a few options to help.



Assuming that your directive IS a child of the HTML where your controller sits:



<div ng-controller=myController>
<my-save-directive></my-save-directive>
</div>


You have a few options.



I'm going to assume that you've got a bunch of long, drawn out business logic in your controller, and a bunch of interaction-handling in your directive... ...I'm also going to assume that you want to hope this directive can be reusable (in an ideal world), or at least, should not be leaking things in and out of it, aside from what you give it express permission to touch.



So if your controller looks like this:



[$scope, $http, function ($scope, $http) {

$scope.doStuff = function () { };
$scope.students = [];
$scope.saveStudent = function (particularStudent) {
$http.post(particularStudent);
};

}]


Then your options might look like this:



//mySaveDirective.js
angular.module(...).directive(mySaveDirective, function () {

var directive = {
template : <button ng-click='save(subject)'>SAVE</button>,
scope : { // <----here's the key bit
save : &,
subject : =
},
link : function ($scope, el, attrs, ctrl) {
// .......
}
};

return directive;

});


That scope property will make all the difference:

Defining it in the directive object (JS) like so...



scope : {
camelName : &,
otherName : =
}


...and using it in the directive's HTML declaration (NOT(!!!) the actual template)



<my-save-directive  camel-name=saveStudent(subject) other-name=student></my-save-directive>


What does that get us?



The & means that the parent controller is giving you a function (or any expression, which will be wrapped in an implicit function), which can be called inside the directive, but will fire in the parent's scope.



<div controller=myController>
<my-directive directive-method-name=controllerFunc(directiveArgName)></...>


So inside of your directive's actual template, you can now write:



<button ng-click=directiveMethodName({ directiveArgName : scopeObj })>


The reason it holds an object with a property with the same name, is because Angular parses the definition of the method the same way it parses function definitions for DI in other places.



scope : {
propName : =
}


Means that you can set up a 2-way binding on that property, between the parent and the directive.

It could be an object or a value, or it could be a method from one end or the other, or a messaging system/event system to communicate.

If one end changes the value, it changes for the other end, too.



So if I'm assuming



// StudentController
$scope.student = {};
$scope.saveStudent = function (student) { };


Then the directive JS can look like this:



// SaveDirective
var directive = {
scope : {
subject : =,
save : &
}
};


And the HTML where the directive is declared (not compiled):



<div ng-controller=studentController>
<div save-directive subject=student save=saveStudent(subject)>


And finally, the button:



<button ng-click=save({ subject : subject })>SAVE</button>


I hope that makes sense.



Also, there are very, very few times you care about $compile.

Almost none, unless you're writing something that needs to do heavy modification to the template, before using it (at which point, why not write a different template?).



Typically, in a directive, you care more about the link method than the compiler.



The difference is that the compiler runs one time on the template, period.

If you use the same directive in 8 different places, the compiler will still only have run once (unless you force it, for some reason).

The link function is run for each instance of the template (the final cloned node that you're given), and you also have access to the directive's scope, and proper linking to everything that sits on top.



...It's 2am, I hope that helped...


[#73162] Tuesday, January 14, 2014, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
bradleymoisesy

Total Points: 121
Total Questions: 105
Total Answers: 95

Location: Nepal
Member since Mon, Jan 4, 2021
3 Years ago
bradleymoisesy questions
Wed, Dec 22, 21, 00:00, 2 Years ago
Tue, Jun 1, 21, 00:00, 3 Years ago
Thu, Jun 11, 20, 00:00, 4 Years ago
Thu, Jan 16, 20, 00:00, 4 Years ago
;