AngularJS: directive timing issue when using Angular routing - angularjs

My application uses two AngularJS directives: a parent directive that contains multiple instances of a child directive. The rendering of HTML by the child directives is dependent on the width of the containing element associated with the parent directive, so the child directive must query the parent (by calling a method on its controller) to discover this width.
This implementation works fine when used in a static page, but it breaks when used as part of a single-page application that employs Angular's routing mechanism.
Specifically, with routing active, the first time the page is loaded, the HTML renders correctly, but when the page content is updated to reflect different model data, the rendering breaks. This only occurs when the width of the containing element is 100%. If it is set to a fixed width, everything works as expected.
Debugging the issue has shown me that the width of the containing parent element is not valid at the time that the child directives are rendered, so I assume I am doing things in the wrong sequence or failing to follow some aspect of Angular best practice that deals with this kind of timing gotcha.
Is there an event that my directives need to wait for before rendering?
Thanks, in advance.
Tim

If i am understanding correctly you are have few child directives that has a width dependency on the parent directive. There are events that you can try on such as $broadcast where the parent directive sends a notification to its children.Once you receive that then you can use $on event and can your child directives.
I know i am not much constructive in my answer but yes if you have built such a dependency.

Related

What is the difference $scope.$parent vs $broadcast?

What is the difference between $scope.$parent and $broadcast?
Everything is different. They're not related at all. Two completely different things - not even the same JavaScript type.
$scope.$parent is a reference to the parent scope object, while $broadcast is a function to broadcast an event.
Basically im writing a common layout.
Inside common layout developer will write his code using ui-view.The common layout will have button events when fired it should change the state of ui-view which is nested.
For this if i use components i think i cant achieve because
Top-framwrok(buttons,titles e.t.c)
Body-developer-this part is an ui-view
Bottom-framwork(border ending and some styles)
So for framwork i will have controller
So when firing any change in framework should trigger developer template also.

Attach additional functionality to parent controller in Angular

I have a dropdown element directive to display in essence a styled dropdown list with additional capabilities.
My dropdown controller has a function called openDropdownItems that get's executed when the list should be displayed.
Then I also have another attribute directive called setInViewWhen that provides an expression when the element should be scrolled into view when condition is true.
<x set-in-view-when="something.item === selectedItem">
This is just an example of some X element with my attribute directive applied.
The thing is that I would like my dropdown list items (LIs namely) to have this directive on them so when user navigates over them using a keyboard, it would automatically scroll them in view when they get passed visible viewport. Whether these items are displayed within a scrollable container or as a whole in a list longer than the browser viewport isn't really relevant.
The main idea is for scrolling to follow dropdown list selection. Whether that should scroll the main window.
The problem
I can make my setInViewWhen directive completely independent but that means that I would have to search for the closest scrollable container whenever condition changes on an item. This seems to be quite a bit of processing that I would like to avoid to repeat (I need to traverse the DOM upwards, checking each node's calculated stylesheet property OverflowY + some additional checks.
This basically seems redundant because whenever I get the closest scrolling ancestor all sibling elements with the same directive could reuse the calculation result.
Question 1
How can I share this knowledge between sibling directives? If I was to fire an event I could not know whether receivers are siblings or not without any additional processing.
Question 2
Instead of checking for scrollable container every time when my directive's condition becomes true I could theoretically change dropdown parent's openDropdownItems to first complete it's original execution an then also execute the scrollability check and use the result of it along with my directive's condition.
I can gain access to dropdown's controller in my directive via directive requires property and adjust it in the post-link phase.
But this also means that I couldn't use my directive outside of dropdown which I would like to as it is a generally usable directive I could attach on several elements in my app to scroll elements into view under certain conditions.
What would you suggest how to do this?
To sum up the comments:
For Question 1, there is no direct way for sibling directives to communicate with each other. I usually create a wrapper parent directive to relay the messages.
As per the comments, the condition something.item === selectedItem introduces a watch; for a list of select items this can be many watches and detrimental to performance. Even if it doesn't occur now, it is a trap and someone may be lured into using this for a long list of items in the future. I would rather have a single watch in the parent of the <li>s and add the "scroll into view" logic there.
With the previous point in mind, you could still have a standalone setInViewWhen directive (seems useful) and have the controller of your X-select replacement directive share code with it. E.g.:
a service containing the common functionality,
an angular value containing a base class (Typescript or JS) and have the controller of both the setInViewWhen and X directives extend from it
or any other solution that is convenient for your case
Related to Question 2: The children could require their parent and change a method in it (this technique is even endorsed by Angular, see ng-model and custom controls where they override ngModel.$render() by replacing it). If you do that however, there would be many children changing the method of the parent, which could lead to a mess.

Default Content before Route Resolution

I'm re-working a website that has a very nested interface requiring several child views. Think of a shopping site, with paging, results and filters. What I'd like to do is render default content for said children views while the results are being resolved from the back-end. However, I can't find a way to insert default content past the first <ui-view>, which of course, makes sense.
To get around this, we are currently using $broadcast in the child state controllers. We moved the resolution out of the resolve event into the controller, which is working, but requires us to make all of our directives use $broadcast as well, or they don't work since the data isn't loaded before they are. It also seems like a very inelegant solution to the issue.
What's weird, is that when I move the resolve function into a child view, neither the parent nor it's siblings views load before the results child view loads. I can't understand that whereas I can understand children views not loading before the parent is resolved.
Is there a way we can work around this? Building in broadcasting into all aspects of our code base seems like an extremely poor practice. Is there a way to show children default content before the parent is resolved, or even render child states' views before their controllers are instantiated?
Use ng-cloak class:
https://docs.angularjs.org/api/ng/directive/ngCloak
The ngCloak directive is used to prevent the Angular html template from being briefly displayed by the browser in its raw (uncompiled) form while your application is loading. Use this directive to avoid the undesirable flicker effect caused by the html template display.

Ionic framework with AngularJs : Can a modal have the same controller as the view that launches the modal?

I am trying to build out a multistep form for a complex object. I use the modal to section out parts of the form. The Ionic examples I could find, appear to assign a different controller to the modal. I would like to keep the view plus all the modals it launches, all of them associated with one controller. Is that possible? I tried assigning to the modal view ng-controller="viewCtrl" where viewCtrl is also the controller of the starting view that launches the modal, but it appears to hang chrome with a high CPU which subsequently necessitates killing the chrome tab.(some sort of cyclic effect by calling the same controller??)
Your advice/insight would be welcome.
I assume that your modal is a directive.
I also assume that you have it placed inside the view (controller scope).
If the above are correct than the directive inherits the $scope properties and methods from the parent controller (a general thing in angular), unless your directive has an isolated scope (if you have the scope property in the directive set to anything but false).
If your directive has an isolated scope you can still pass data from the parent using attributes on the directive. If you want to pass something from the directive to the parent you can use $emit.
You can also access the parent from the directive using $parent but I would suggest against it.

Sharing isolate scope with nested directives in Angular

I want to have a custom directive that is reusable and creates an isolate scope so it can be used anywhere (as long as the consumer uses the API defined by the directive). Then, I want the consumer to easily be able to mix and match different reusable pieces that fit within the main reusable directive.
The situation I'm working with is a drop down menu. The main directive would isolate the scope and define the API for the dropdown as a whole. The inner directives would allow the consumer to choose whether they want a button that opens the menu, a search box/input field that opens the menu, etc. Then they could also choose what menu style is used:
<dropdown items="..." selected-item="...">
<dropdown-button>(Transcluded button text here)</dropdown-button>
<dropdown-icon-list></dropdown-icon-list>
</dropdown>
The parent directive/controller would handle state/communication for the inner pieces (ie. the button might trigger the "open" state, and the list would respond by opening). In other words, the parent directive would provide a single place for the consumer to define behavior and isolate scope from the rest of the page, while the nested directives would change shared state/respond to changes in shared state based on their role.
I actually had this working by using an isolate scope on the main "dropdown" directive and then inheriting scope with the nested directives (didn't specify "scope: ..." on the nested directives). But, with Angular 1.2, things have changed such that the isolate scope of the parent is truly isolated--the children inherit the scope that exists outside the parent directive, rather than sharing its isolated scope.
What is the Angular way to accomplish such a thing?
I've started retrofitting my existing code to share the controller from the parent directive with the nested children, but I feel that's the wrong way to go once I get into the situation where the children need to listen for changes on the shared scope... The only way I can see to do that would be to pass a callback function from the nested directives into the shared controller which it would bind to a $scope.$on method. Seems like the wrong path to head down.
There’re 3 types of prefixes AngularJS provides.
"#" ( Text binding / one-way binding )
"=" ( Direct model binding / two-way binding )
"&" ( Behaviour binding / Method binding )
All these prefixes receives data from the attributes of the directive element and provide communication between directives. please visit below link for similar question.
Visit https://stackoverflow.com/a/33024209/4348824

Resources