How to wait for controller is rendered in Angular.js - angularjs

I'm using a custom jquery plugin which transforms table to a tree. And when i'm loading data from ng model i need to recall plugin's constructor. but i can not find that event, when i need to call that.
I've tried to $watch model variable - doen't work well

You should create a new directive instead of doing this in a controller.
By using a directive, you'll be sure that the code located in its link function is applyed after DOM complilation.
It is intended to do what you want.
see http://docs.angularjs.org/guide/directive

Related

How can an Angular directive have a 'native' parent state when it is compiled elsewhere?

I use ui-router to create routes with multiple HTML pages.
I have custom "target" directives within these pages that use $state.current in various ways.
But I also have other custom "lookup" directives in other states which load these HTML "templates", find these "target" directives, compile them and insert them into the DOM.
The problem I am having is that when the HTML content is compiled in these second directives, $state.current obviously refers to whatever state the application is in when it is compiled, whereas I would like the directive to compile as if it was in its "native" state.
Is there any (easy-ish!) way to get a reference to the target directive's "native" state? i.e. the state connected to the .HTML file which the directive is in? Is there a method (angular, jquery, native js or anything else) to get from the directive to the HTML template file? Then I could do a reverse lookup on the state objects. element.ownerDocument can get the URL of the current state, but not the HTML file of the template.
Alternatively, if the second directive had a reference to the "target" state, how should I modify the "target" directive so that it takes a state reference when it is compiled in both scenarios? Something in the compile function perhaps?? - but the docs don't seem to cover this kind of use case... I could do with a pointer in the right direction.
I hope that all makes sense. I have looked around for similar answers, but I guess this is an unusual use case? I'll knock up a Plunker shortly to help illustrate...
When you compile HTML using $compile, you pass in a scope object. Instead of using $state.current within the directive, could you attach the "state" you need to the scope object that you're passing in?

Angular Directive not executing on UI Bootstrap Modal open

I have a one-page site that I am building out and this is my first time using Angular on a site. Building it on top of Laravel too for the backend but that is beyond the scope of this question.
I need to be able to open a modal on a main page view which will add a new resource (e.g. a new client) or edit a resource. I want to somehow get the form's html inside the modal body when the $uibModal.open()'s controller is called and set the $scope.modalBody equal to the injected items.modalBody (the only way this works is if I use:
$scope.modalBody = $sce.trustAsHtml(items.modalBody);
The only problem now is that anything inside the HTML body, Angular will not use it's magic and do any data-binding. It is still in the raw form of
{{ object.property }} or since I'm using Laravel and avoiding conflict with the Blade template engine:
<% object.property %>
See screenshot:
screenshot
I have been banging my head against the wall on this one...I have tried putting $scope.$apply() in my directive and my controller, neither of which worked. I have a feeling that is the source of my problem though. I have also tried making the html just a <new-client></new-client> directive and using templateUrl: 'views/clients/add.php' which would be ideal, but the template is not being included inside the <new-client></new-client>.
I'm using ui-bootstrap 0.14.3 and Angular 1.4.8.
Could this be a bug? Or am I doing something wrong? Anyone have a better way of getting a form into my modal? Let me know what code you want to see so I don't clutter this post with unnecessary code blocks.
I have come across a similar issue with using jQuery's AJAX to receive template strings and append it to a server.
So when HTML is added via jQuery, bound html string, etc., angular doesn't know it needs to automagically compile this data.
What you need to do is use the $compile service, to $compile your html and then attach the correct $scope to it:
`$compile('jQuerySelectorReturningHtmlOrAnHTMLStringThatNeedsToBeCompiled')($scope);`
There are multiple examples in Angulars Documentation for $compile that can give you an idea of what is happening. I think by what you have described the same thing is happening here in your situation.
The key is to call this $compile service function after the html has been bound to the page.
EDIT:
There are a few other options based on some comments, that will serve as a viable solution to rendering this content on your view. For example a directive that takes a string attribute representing the HTML string of your desired view.
1. Modify your directive template in the compile step:
You have the ability to modify your template before the directive compiles and binds any attributes to it, to that directives scope:
app.directive('myAwesomeCompileStepDirective', [myAwesomeCompileStepDirectivef]);
function myAwesomeCompileStepDirectiveFn() {
return {
restrict: 'EA',
compile: function compileFn(tAttrs, tElement) {
//Here you can access the attrs that are passed into your directive (aka html string)
tElement.html(tAttrs['stringThatYouWantToReplaceElementWith']);
return function linkFn(scope, element, attrs, controller, transcludeFn) {
//if all you want to do is update the template you really don't have to do anything
//here but I leave it defined anyways.
}
}
}
}
You can view a file I wrote for a npm component which uses this method to modify my directive template before it is compiled on the page & you can also view the codepen for the complete component to see it in action.
2. Use $compile service to call $compile in link function using directive attrs.
In the same way as the aforementioned method, you can instead inject the $compile service, and call the function mentioned above. This provides a bit more work, for you but more flexibility to listen to events and perform scope based functions which is not available in the compile function in option 1.

How to use data-image and data-zoom-image attributes in angularjs

I need to add elevateZoom image slider to my Angular application. Following is my html code.
<img id="zoom_03"
ng-src='{{galaryImages[0].w320}}'
data-zoom-image='{{galaryImages[0].original}}'/>
Here
{{galaryImages[0].original}}
and
{{galaryImages[0].w320}}
is being loading dynamically using Ajax call from controller. ng-src is working successfully. but since i have used data-zoom-image as larger image it is executing before controller fetch the results because of that elevateZoom script is not working properly because zoom-image is assign to angular expression which is {{galaryImages[0].original}}. What is the solution to overcome this issue? are there any way to handle attributes like data-zoom-image as angular handling ng-src? or any other solution.
Thanks
Without knowing what elevateZoom is really, I can suggest you do either 1 of 2 things. The first is create a custom directive to handle this. The second is use ng-attr.
With ng-attr, you can do something like
ng-attr-ng-src='{{galaryImages[0].w320}}'
ng-attr-data-zoom-image='{{galaryImages[0].original}}'
I'm not sure how elevateZoom, if it's just taking a snapshot of your variables, then you will have to do something else. If it's built for angular and binds to the variables, then it should work.
If you want it to wait, you can do soethimng like toggling a boolean like
<img id="zoom_03" ng-if="isLoaded"
Where you set is loaded to false by default, then when your ajax call is done you set it to true
.complete(function() {
//apply your logic
$scope.isLoaded = true;
ng-if will take it off the dom completely, and will evaluate when you bring it back on by setting isLoaded to true.
Note: either way you do this I still recommend you bring this into an angular directive, it looks like this is a jquery plug in. The best thing to do is to put it in a directive and apply the logic through the directive, or find one already built for angular. You will find it very difficult to use jquery logic into angular if you don't have a directive. For instance this plug in might be firing on document.ready to look for the custom vars, in which case the ng-if wont work.

pass parameter to Angular directive template function post-post-link, using $scope, GET or whatever

I am trying to write a directive that will format content for modal display (using Bootstrap classes) if given a certain parameter, and as standard view if not. I have this working for a view loaded directly, toggling on a URL param (?modal) available to $routeParams and/or $location.
I want to use this toggle-able template as a "pipe" for other templates. However, the intended content URL will never be the visible URL when used as a modal. I can't get it working when loading the view with $modal.open or ngInclude, because $routeParams/$location has data for the including page, not the included one.
I put this in a Plunker, but because Plunker also doesn't provide the URL param, the modal view isn't available.
Does Angular provide a means to change the template or templateUrl much later in the process? For example, could I use $scope, either from a controller or on the directive, itself?
Clarification: The goal here is to have one template/partial for each component, with that template used either as a standalone or a modal, based on some switch. The _modal and _alone partials in the Plunker convert the component template into the desired state.
$modal.open takes a single object parameter one of the properties of this config parameter is templateUrl
http://angular-ui.github.io/bootstrap/
So you can create the config object and open the modal with any template you need.
Dan Wahlin uses this technique for a dialog service and then in this article goes on to demonstrate a full modal service
http://weblogs.asp.net/dwahlin/building-an-angularjs-modal-service
There were a couple of issues with your code:
First of all the use $routeParams if you don't use ngRoute's $routeProvider.
In your case, it might be easier to use $window.location.search (and compare it against ?modal).
That said, in order to properly display a Bootstrap modal, you need Bootstrap's JS file (which in turn requires jQuery) and you also need to create the modal (e.g. by calling $('.modal').modal()).
Take a look at this modified demo.
For better intergration with Angular's components, you might want to look into UI Bootstrap.

Controller not loading when using jQuery.append

I'm currently using jQuery to display modal windows, the function basically builds some HTML and then does $('#myElement').append(modalHtml);
Inside that modal HTML I have <div ng-controller="MyController">...</div> however when the modal is displayed the controller doesn't seem to get initialized. Is this because it's being added to the DOM outside of angular's scope? If so is there anyway when I run that code I could notify angular to look out for changes?
The breakdown of how it is at the moment is Angular runs loadModal() through an ng-click on an element. loadModal() calls modal(), and modal() builds the html and adds it to the DOM. Modal is in a script of just standalone helper functions.
The modal controller won't be called because you're not parsing or compiling the appended DOM code with Angular. Hence, Angular will not 'notice' this change and as a result it will not run any controllers or directives in the added DOM. The best way to solve this kind of problems is by adding a custom directive.
As you're trying to make a modal work, you could also take a look at existing modal adaptations for Angular, such as the one in AngularUI.

Resources