Partially isolated scope angular - javascript

I have a directive that i want to include multiple times on a page.
I also want to control this directive from the parent controller.
To give an example, the directive is a modal has a transcluded partial in it. This partial has a form that sends a message.
I want to dictate what that form does from my parent controller however when i isolate the scope (so that i can have more than one of these directives per page) i can no longer access the form object that angular creates.
im open to suggestions
html page
<page controller="pageCtrl">
<modal partial="/path/to/partial1"></modal>
<modal partial="/path/to/partial2"></modal>
</page>
html partial 1&2
partial1.html
<form name="formName1"></form>
partial2.html
<form name="formName1"></form>
JS
app.directive('modal', function(){
return {
restrict: 'AE',
transclude: true,
replace: true,
scope:true,
templateUrl: '/path/to/modal.html',
link:function($scope, elem, attrs){
$http.get(attrs.partial, { cache: $templateCache })
.success(function(response) {
element.find('[ng-transclude]').append(response);
$compile(element.find('[ng-transclude]').contents())($scope);
});
}
}
});
app.controler('pageCtrl', function(){
$scope.submitForm1 = function(data){
if($scope.formName1.$valid){
//DO SOMETHING
}
}
})

OK so after typing it all out i realized how to do such a thing.
My goal was to isolate the scope of the directive but not the scope of the form inside.
So all i had to do was change what scope my included form/modal content was compiling against;
$compile(element.find('[ng-transclude]').contents())($scope.$parent);
Instead of;
$compile(element.find('[ng-transclude]').contents())($scope);
Thanks anyway
-James Harrington

Related

Error: Template must have exactly one root element when creating a custom directive

I want to make a simple directive that has a button that will show if the cursor is placed over it. However, every time I include this new directive into my index.html I receive this error in return.
Here is the following error:
Error shown on console
Here is my template code:
<div>
<button ng-show="ishovering">DELETE</button>
</div>
Here is my directive code:
app.directive('deleteArea',function(){
return {
scope: {},
require: 'ng-show',
restrict: "AE",
replace: true,
templateUrl: "./templates/delete.html",
link: function(scope,elem,attrs){
elem.bind('mouseover',function(){
elem.css('cursor','pointer');
scope.$apply(function(){
scope.ishovering = true;
});
});
}
};
});
Any help is appreciated, thank you.
Just use bootstrap for angular called ui.bootstrap .
Use the popover directive that will give you the effect you need.

Is there a way to load data into script

So in Angular i'm trying to do
$scope.data = "<script> alert('hi'); </script>";
But unfortunately that doesn't work. I also tried to add ng-bind-html but without any results.
{{data}}
also I tried to load data in a script tag but that also seems not to work. Is there a way to avoid this all? For example
$scope.data = "bob";
-
<script>
var name = {{data}};
</script>
You could create a directive that will load the script into DOM dynamically.
Markup
<load-script ng-if="data" data="data"></load-script>
Directive
app.directive('loadScript', function($compile){
return {
restrict: 'E',
scope: {
'data': '='
},
link: function(scope, element, attrs){
element.append($compile(scope.data)(scope))
}
}
})
Working Plunkr
Your $scope will be already either within a <script> block or in a Javascript file.
Now, when/how do you want the alert to be called? If I understand correctly what you're trying to do, here's how to do it:
<div ng-click="doAlert()">
Click here to see an alert
</div>
and in your controller:
$scope.doAlert = function() {
alert('hi);
};

Call Javascript After Directive Renders DOM for ShareThis

In an Angular (1.3) app, I am displaying list of records using ng-repeat. There is a directive with a template inside the ng-repeat. Within the template I'm using ShareThis controls which are activated after the DOM is loaded.
On initial load of the app, the ShareThis Javascript works correctly and activates the buttons. On route change it does not activate. I've found to references to activate the controls manually via stButtons.makeButtons() or stButtons.locateElements();, but I'm unsure where to call this function in the directive or page cycle. I've tried within:
the directive link function - using $timeout or scope.$watch
the template <script>stButtons.locateElements();</script> - activates before model binding
the controller after binding - activates before DOM rendered
My understanding is the function to activate needs to be called after binding and after DOM rendering, but Angular does not know when the DOM is ready. There is a method to dynamically render the ShareThis controls using only Javascript, but I want the HTML defined in the template not Javascript for this case.
I've seen several questions out there related, but none of the answers seem to work 100% for my scenario (and many are broken as of Angular 1.3).
item-list.html (view)
<div ng-repeat="item in vm.itemList">
<item-directive item="item"></item-directive>
</div>
item-list.cs (controller)
{ ... vm.itemList = getItems(...) ... }
item-directive.js (directive)
(function () {
angular.module('app');
function itemDirective() {
var directive = { templateUrl: 'item.html', link: linkFunc, controller: ItemDirective };
return directive;
function linkFunc(scope, element, attr, ctrl) { var item = scope.item }
}
ItemDirective.$inject = ['$scope'];
function ItemDirective($scope) { ... }
}
item.html (directive template)
...
<div class="item-share-section">
<span class='st_sharethis_large' st_url="{{vm.item.url}}" st_title="{{vm.item.name}}"></span>
</div>
...
if I understood well, you want to call the function after the dom is completely render, right? Try this inside the postLink of your directive:
$scope.$watch('viewContentLoaded', stButtons.locateElements())
While my solution is a little hackish, I still prefer it over using $watch, since that is inefficient. Instead, I initialize the function which loads the buttons when the particular view you want to load the buttons with is rendered. The technique is as follows:
Here is the function which you should put in your controller:
$scope.loadShareThis = function() {
stButtons.makeButtons();
}
You'd then add to your item-list.html as such:
<div ng-repeat="item in vm.itemList" ng-init="loadShareThis()">
<item-directive item="item"></item-directive>
</div>
The dynamic URL's might give you additional problems, but that's another issue all together.

Initialize Zurb Foundation 5 in an AngularJS Directive

I've created three plunkrs to illustrate my problem. I'm trying to create an AngularJS Directive that will initialize foundation and apply the necessary javascript to the loaded template. At first I was trying to use ngInclude to add the Foundation 5 nav bar to all of the pages of my website. The top bar works as expected when the html is directly applied to a partial. When the html is added in a directive, such as ngInclude, the top bar looses all its functionality. I suspect that this was because foundation is not getting initialized after the template is added by the directive. As a solution I created a custom directive that would initialize foundation and compile the html template. Initializing foundation the way I do freezes the application. Anyone have a solution to this?
Trying to achieve this without resorting to Angular UI.
Example 1: HTML directly applied to the view. Works as expected, when you click on the menu dropdown the pages are displayed.
http://plnkr.co/edit/aQc6j2W9MpRuJo822gAF?p=preview
Example 2: ngInclude used to load template to dom. No functionality is achieved, when you click on the menu dropdown nothing happens.
http://plnkr.co/edit/fSS3FfYKFilMXsIkYUHg?p=preview
Example 3: Created separate directive to replace ngInclude that would initialize foundation, compile, and load the template to DOM. Can't provide a plunkr because it would just freeze up, but here is the code.
.directive('testdirective', function($compile) {
return {
restrict: 'AE',
templateUrl: 'partials/includes/nav.html',
link: function(scope, element, attrs) {
$compile($(document).foundation())(scope);
}
}
})
applied in partial by:
<div testdirective></div>
Do this:
link: function(scope, element, attrs) {
$compile(element.contents())(scope);
$(document).foundation();
}
If you compile the element itself, you create an infinite loop:
$compile(element)(scope); //fail
Always be sure that you only compile the element's contents:
$compile(element.contents())(scope); //win
It seems that you are compiling the whole document and creating the infinite loop.
You can probably just do this:
templateUrl: 'partials/includes/nav.html',
compile: function() {
$(document).foundation();
}
because the template will be automatically compiled so you don't have to do it manually.
Note: it's best practice to inject and use Angular's $document, which is a wrapper for document that helps in testing. $($document).foundation();

Put array into angular directive

I have got a piece of code in an angular application, that writes a navigation tree into a <div>. This tree may change its size depending on the model of mymodule.tree.folders. Now I want to write a directive class="scrollable", that adds the functionality of jquery.nicescroll to the wrapping <div>:
<div class="scrollable">
... here is my resizing tree ...
</div>
Now, I have to call the resize() function of nicescroll each time, the tree model mymodule.tree.folders changes. This is necessary to make this library work as expected, after the content changes its size.
My question now is: How do I put the model mymodule.tree.folders (it is an array) into my directive to be able to $watch() it there? I would like to write something like this:
<div class="scrollable" scrollable-watch="mymodule.tree.folders">
... here is my resizing tree ...
</div>
...in my template. Is this possible, to fetch this model from the templates scope or do I have to serialize the whole tree into an extra variable?
I found a way to access the model through the $parent scope:
'use strict';
angular.module('shared.directives.scrollable', []);
angular.module('shared.directives.scrollable').directive('scrollable', function() {
return {
restrict: 'C',
link: function(scope, element, attrs) {
scope.$watch('$parent.' + attrs.scrollableWatch, function(newValue, oldValue) {
console.log('Model changed!');
}, true);
}
};
});
It seems a bit hackish to access the parent scope, but because this is allways the caller scope, I think it is okay.

Categories