Angularjs remove custom directive and child directives from DOM - angularjs

I have a single page angularjs app. I use $routeProvider to load up custom directives shown in the code below.
Now each custom directive loaded is made up of additional sub custom directives. All the custom directives have isolated scopes.
What I need is when the view changes is the scope to be destroyed as well as remove the directives from the DOM under the current view. I've got as far as the following code. Can this be achieved with Jquery lite and/or angularjs only? If so how do I remove the parent and child directives from the DOM for a particular view? Thanks in advance.
Custom Directive Form
angular.module("form", [])
.directive("form",['$http','$rootScope','$location', function($http,$rootScope,$location){
return{
link: function(scope,element,attrs){
//functions go heere
//destroy scope and remove from DOM on route change
$rootScope.$on( "$routeChangeSuccess", function(event, next, current) {
if($location.path()!=='/form'){
scope.$destroy();
console.log('This should not be displayed on route change');
}
});
//function and scopes go here
},//return
restrict:"A",
replace:true,
templateUrl:"partials/form/form.html",//template
transclude:true, //incorporate additional data within
scope:{}
}//return
}])
ng-view/routeProvider
app.config(['$routeProvider',function($routeProvider) {
//configure the routes
$routeProvider
.when('/',{
// route for the home page
templateUrl:'partials/login/login.html',
controller:'loginCtrl'
})
.when('/home',{
// route for the home page
templateUrl:'partials/home/home.html',
template:'<div home></div>'
})
.when('/company',{
// route for the sites& companies
template:'<div company></div>'
})
.when('/form',{
// route for form
template:'<div form></div>'
})
.otherwise({
//when all else fails
templateUrl:'partials/login/login.html',
controller:'loginCtrl'
});
}]);

Please see this reference:
How to manually take an Angular directive out of the DOM
As per the source reference :
Steps:
1. Delete the directive's scope
2. Delete the directive's DOM
childScope.$destroy(); //IF THE DIRECTIVE WAS CREATED DYNAMICALLY OR ELSE WE MAY USE angular.element(DIRECTIVES-DOM).scope().$destroy()
$('.my-directive-placeholder').empty(); //DELETE DIRECTIVE'S DOM

Related

scope issue with ng-view, parent controller, custom directive

I'm so confused about my situation. Let me briefly introduce my situation.
HTML structure. (It's just structure, full HTML is more than that but there is no any other controller except "pageController")
<body ng-app="app">
<div id="wrapper" ng-controller="pageController">
<div id="menu">
<a>.........</a>
</div>
<div id="mainView">
<ng-view></ng-view>
</div>
</div>
</body>
Of course, I properly set router.
var app = angular.module("app", ["ngRoute"])
.config(function($routeProvider){
$routeProvider
.when("/about", {
templateUrl: "about.html"
})
.when("/summary", {
templateUrl: "summary.html"
})
.when("/company", {
templateUrl: "company.html"
})
.when("/remote", {
templateUrl: "remote.html"
})
.when("/personal", {
templateUrl: "personal.html"
})
.when("/academic", {
templateUrl: "academic.html"
})
.otherwise({
redirectTo : "/about"
});
});
I didn't set any controller now. I put each controller as "pageController" before but I removed now because I think pageController will be automatically inherited as long as pageController is in parent element.
And I made custom directive.
app.directive('imageLoader', function(){
return{
restrict:'A',
link:function(scope, elem, attrs){
elem.bind('click', function(){
var fileName = "img/portfolioImages/" + attrs.ori;
scope.$parent.$parent.modalImgSrc = fileName;
scope.$parent.$parent.isModalOpen = true;
scope.$parent.$parent.$digest();
});
}
};
});
In injected html in ng-view, there is no any other controller, but it dynamically generate <img> tag like below
<div class="project-image-div">
<img image-loader ng-repeat="aImgSrc in remoteImageFiles[0]"
data-ori='{{aImgSrc}}' class='project-img-s'
ng-src='img/portfolioImages/{{aImgSrc.substring(0,aImgSrc.lastIndexOf(".")) + "_s" + aImgSrc.substr(aImgSrc.lastIndexOf("."), 4)}}'>
</div>
remoteImageFiles[0] is json object saved in pageController scope. And these dynamically added img tags are completely fine.
THE PROBLEM
As you can see in <img> tag, I am using custom directive image-loader. In directive code, I expected "scope" is same scope as pageController as long as there is no any other controller inside ng-view and I didn't give any option for scope in the custom directive.
But I printed scope object in console, I can access pageController scope object as parent of parent... WHY?????
scope.$parent.$parent.modalImgSrc = fileName;
scope.$parent.$parent.isModalOpen = true;
scope.$parent.$parent.$digest();
Thank you for reading my long post... please help... I am spending 2 days for this..
You can see full code in my personal web site. I am noob to angularJS. I am converting JQuery version of site to pure angularJS version to learn AngularJS.. It's in progress.
AngularJS version..(converting now)
http://bear-mj.com/MJKim
JQuery version..(all working)
http://bear-mj.com/MJKimJQuery/
You have 3 levels of scope created. Remember, both ng-repeat and ng-view create a new scope. In this area of your app - inside the directive:
scope is the ng-repeat scope
scope.$parent is the ng-view scope
scope.$parent.$parent is the pageController scope

Find element in angular template from controller

I'm working with a directive.
Here is simple format of my directive:
angular.module('app',[]).directive('companylookup', CompanyLookupDirective);
function CompanyLookupDirective() {
return {
templateUrl: '<input id="foo"/>',
controller: 'CompanyLookupController',
controllerAs: 'vm'
}
}
I want to find input element with jquery in my controller (CompanyLookupController.js) like this:
var foo = $('#foo');
// decorate foo element using igniteui lib
$('#foo').igCombo({ datasource: ...});
But $('#foo') always return null. I can try to delay finding element with $timeout service to wait until element exist. But I don't want to do this so much times in my app in concern of performance.
Is there any way we can reference template elements in angularjs from a controller?
in template URL use escape character before quotes ,
templateUrl: '<input id=\"foo\"></input>'
Also i agree with #Robert Goldwein and if you absolutely have to, use link to manipulate DOM
EDIT : Help on link and compile functions.

angular ui modal can NOT refer to parent scope

i am using angular ui modal to create modal in my project.
Everything works fine until I need to refer to variable in parent scope. see plunker code
It seems like modal can't access parent scope. Is there anyway to overcome this?
Angular UI's modals use $rootScope by default (See the documentation here).
You can pass a scope parameter with a custom scope when you open the modal – e.g. scope: $scope if you want to pass the parent scope. The modal controller will create a sub-scope from that scope, so you will only be able to use it for your initial values.
You'll need to refer to the parent scope in your $modal options. Angular documentation
Corrected Plunker Version
Below is also a code snippet of what I added to make it work.
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
scope:$scope, //Refer to parent scope here
resolve: {
items: function () {
return $scope.items;
}
}
});
You can add an ID to the parent div and use his scope.
<div id="outerdiv" ng-controller="OuterCtrl">
<h2>Outer Controller</h2>
<input type="text" ng-model="checkBind">
<p>Value Of checkbind: {{checkBind}}</p>
And set up a "fake" binding within the controller
//init
$scope.checkBind = angular.element(document.getElementById('outerdiv')).scope().checkBind;
$scope.$watch('checkBind', function (newValue, oldValue) {
//update parent
angular.element(document.getElementById('outerdiv')).scope().checkBind = $scope.checkBind;
});
See http://plnkr.co/edit/u6DuoHJmOctFLFhvqCME?p=preview

How to use the same controller for modal and non-modal form in Angular UI Bootstrap?

I've got a modal with a registration form. The same form should be displayed at the bottom of the landing page not in a modal.
Currently my controller that handles registration modal takes $modalInstance as one of its parameters along $scope etc. If I add ng-controller="SignUpCtrl" to an element in the landing page, it doesn't work, because the controller wasn't created via $modal.open method and so Angular complains about Unknown provider: $modalInstanceProvider <- $modalInstance.
I've got a service for registering users (authService.signUp(data).then/catch...), but the controller itself does a bit more - handles input, emits events (e.g. with translated error messages), sets cookies etc.
What's the best way to handle such case without duplicating almost whole controller code? Should I move the code from controller into yet another, higher-level service?
After struggling for a long while I found a easier trick to reuse our Controller for both modal and normal case.
I found that we can pass caller's scope to modal controller, so I pushed modalInstance into $scope and passed it to the modal controller.
Now you don't have unknown provider problem because $scope is a well known one.
Below is an example:
CallerController = function($rootScope, ...) {
var modalScope = $rootScope.$new();
modalScope.modalInstance = $modal.open({
templateUrl: tempUrl,
controller: ReusableModalController,
scope: modalScope // <- This is it!
});
modalScope.modalInstance.result.then(function (result) {
// Closed
}, function () {
// Dismissed
});
};
ReusableModalController = function($scope, ...){
var dataToSendBack = 'Hello World';
$scope.modalInstance.close(dataToSendBack);
};
Cheers!
If you are using ui-router you can easily use the resolve from ui-router to provide a $uibModalInstance (was $modalInstance before):
$stateProvider
.state('conductReview', {
url: '/review',
templateUrl: '/js/templates/review.html',
controller: 'yourController',
resolve: {
$uibModalInstance: function () { return null; } // <- workaround if you want to use $uibModalInstance in your controller.
}
})
That way you can use your modal controller like a normal controller. If you inject $uibModalInstance in your controller it will be null.
If you want to use same controller for both modal form as well as landing page form, make use of
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
You can get all the data from modal form in selectedItem and use this in landing page form.
Also, how do you open the modal. If it is through a button, bind that ng-model to open modal using $modal.open.Don't create separate controller for your modal.Use the same one as your landing page. This way you can use 1 controller to open modal as well as other function after the modal is closed.
PS: Code snippet given here is from angular ui's page. Check that page's documentation for selectedItem

loading the angularJs directive through partial

I am new to AngularJs and struck with an issue. I have "index.html" where I need to have the main section loaded via the <div data-ng-view=""></div>. Now, the data inside the view will be populated by the controller using the below code
.when('/',
{
controller:'controllers.IndexCtrl',
templateUrl:'/partials/index-partial.html'
})
Inside the index-partial.html file I have used the custom directive linke below:
<custom-carousel/>
The code for the carousel is below:
myApp.directive('customCarousel', function() {
return {
restrict: 'E',
replace:'true',
templateUrl: "/partials/carousel.html",
link: function(scope, element, attrs) {
$('.my-list').click(function(){
$('.my-list').removeClass('active');
$(this).addClass('active');
});
}
};
});
The issue with the above approach is that the jquery code inside the directive gets called twice and hence the toggling of the selected li does not work.
I have below questions:
Is the jquery function inside the directive called twice because its called from the partial and once again during the ng-view?
Whats the reccommended way of handling this scenarios?
Whats the best approach to fix this issue. If I remove the templateUrl from the controller and directly use the custom-carousel inside the html, this works perfectly but I want to load the directive using the ng-view and not directly in the index.html file.
Please let me know the best approach to solve this issue.

Resources