viewContentLoaded - Without duplicating code per each controller - AngularJS - javascript

Hey all I'm trying to get a feel for angular and have ran into a little snag.
I have a container structure like the following:
<div class="main-container" ng-view>
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
Before I implemented Angular I just had a simple script that would check the height of the window and set the height of the left column and right column divs accordingly.
With angular there is probably a better way to do this then attaching an event function to the window object. Basically I want to fire a function everytime a new view is rendered but not duplicate the below code in all of my angular controllers like so:
$scope.$on('$viewContentLoaded', setColumnHeight);
Any help would be appreciated. Thanks!

I've solved this problem in my app by having a root "Application Controller" at the top of the DOM tree. For example:
<body ng-controller='applicationController'>
...
<div class="ng-view"></div>
...
</body>
applicationController is always there, and can set up bindings on its scope when it is created.

How about putting that event listener on the root scope:
$rootScope.$on('$viewContentLoaded', setColumnHeight);

You could use something like this:
<div class="main-container" ng-view>
{{ setColumnHeight() }}
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
and it will check the height every time a render is made, however, this seems to be a bit over processing.
The best approach would be to only update the height from both columns when the height of one of them changes. For that you could use DOM Mutation Observers, however they are not yet available on all browsers. If that's not a problem for you, check the mutation-summary lib.
If you are using jQuery you can also try this: https://github.com/jqui-dot-net/jQuery-mutate (examples here).

Related

Setting raised = true to an ember button when on current page/template

<div class="flex">
<div class="layout-row layout-align-end-center">
{{#paper-button href="overview" raised=true primary=true}}Overview{{/paper-button}}
{{#paper-button href="incomes"}}Incomes{{/paper-button}}
{{#paper-button href="expenses"}}Expenses{{/paper-button}}
{{#paper-button href="settings"}}Settings{{/paper-button}}
</div>
</div>
So I am trying to set the raised=true whenever I am on certain page/template. The above code is from my application template. Is there any way of doing this using JS/Ember or should I just do it manually in each of my templates?
I think the best way to go is to write a custom component wrapping paper-button. ember-route-helpers gives you nice helpers to do that:
{{#paper-button
onclick={{transition-to #route)
href=(url-for #route)
raised=(is-active #route)
primary=(is-active #route)
}}
{{yield}}
{{/paper-button}}
Then you can use that component with {{#your-component route="settings"}}Settings{{/your-component}}.
It's important to understand that you should pass both the action and the href. Because then when people click on the button it will make a transition and dont reload the entire page, but rightlick->open and screenreaders are are not broken.

Angular 1 how to properly include external component inside ng-include?

Situation: I have a view where I'm including a fragment with ng-include. The fragment loads perfectly and works as expected when inside view where controller is defined.
My problem is, that when I want to include external component inside the "ng-include" fragment "myView.html", it doesn't show up. When including it inside the main view where the controller is, it shows up and works as expected.
Main view:
<div ng-controller="MyController">
<div data-ng-include src="'views/myView.html'"></div>
<!-- When loaded here, the component shows up -->
<!-- <div id="componentDiv"></div> -->
</div>
Fragment "myView.html":
<div>
<div id="componentDiv"></div>
</div>
The component is loaded inside the "MyController", where "componentDiv" is the "id" of "div" where the component is placed:
var testObj = new TestObj({"container": "componentDiv"});
Trying to do this to be able to use this fragment with full functionality in several places.
Any ideas or suggestions what to look up or try?
IMHO I think that by saying "...to be able to use this fragment with full functionality in several places" you just answered your question. What you need is to build a custom directive and use it in any place you like.
see directive samples e.g. Angular documentation on directives

Can I use a JQuery plugin from within an angularjs directive?

I'm quite new to javascript in general. I've spent the past couple of weeks building a front end with Angular.js.
I have a number of directives I've defined that sit on my page, Angular has been great for this.
Here's what my main page looks like:
<body class="body" ng-controller="OverviewController as overview" font-size:1em>
<sidebar-menu ng-controller="PanelController as panel"></sidebar-menu>
<div id="content" >
<div>
<div class="list-group">
<div class="list-group-item" ng-repeat="site in overview.sites" ng-click="">
<div class="item-heading">
<h3>{{site.name}}</h3>
<p>Address: {{site.address}}</p>
Click Here
</div>
<installationsite-panels ng-controller="PanelController as panel"></installationsite-panels>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('.paulund_modal').paulund_modal_box();
});
</script>
</body>
Note the javascript function to call a modal box at the bottom, using this tutorial.
I've spent the past few days trying different tutorials to get modals to work in my webapp, but with no success. I think it's down to my lack of understanding of Angular and Javascript in general.
In any case, I've managed to get this tutorial to work using JQuery, and when I click on the link, the modal opens as expected.
However, I don't want to call this modal from here. I want to call it from a directive that's embedded within the <installationsite-panels> directive in the above code, which looks like this (just a single section shown here):
Device Statuses
<div>
<div class="device-icon-group">
<div class="device-type1-icons" ng-click="panel.showDevices(3)" ng-show="showtype1Red"><img src="img/type1red.png" style="width:50%; height:50%;"/></div>
<div class="device-type2-icons" ng-click="panel.showDevices(3)" ng-show="showType2Red"><img src="img/type2red.png" style="width:50%; height:50%;" /></div>
</div>
<div class="service" ng-click="panel.showDevices(3)" ng-show="showService">
<b>{{panel.getServiceDeviceCount()}} device needs servicing</b>
</div>
<div ng-show="showServiceList">
<device-list-service></device-list-service>
</div>
</div>
The directive <device-list-service> shows a list of items like so:
<div ng-controller="DevicesController as deviceList" font-size:1em >
<div id="device-list-group">
<div id="device-list-group-item" ng-click="" ng-repeat="device in deviceList.devicesService">
<div ng-class="device.status"><img src="{{(device.type == 'type1') ? 'img/type1white.png' : 'img/type2white.png'}}"> </div>
<div class="device-params">
<b>ID: </b> {{device.id}}<br />
<b>Type: </b> {{device.type}}
</div>
<div class="device-params">
<b>Location: </b> {{device.location}}<br />
<b>Action: </b> {{device.action}} <br />
</div>
</div>
</div>
</div>
I want to show the modal when the user clicks on one of the list-group-item 's, and display some data relating to that item.
The modal works fine from the top level in the main app, but I cannot call it from within any of the directives. How can I do this?
Is it possible, or do I need to scrap my JQuery modal and do it the Angular way, which hasn't worked for me for the past few attempts.
Don't use jquery modals. You can, but you shouldn't.
Instead, I recommend using Angular UI, which has a pretty usable modal implementation: https://angular-ui.github.io/
Second alternative: if you don't like Angular UI, then use AngularJS + Bootstrap, and create your own custom directives
Third alternative: Use jQuery.
If you still want to go with the 3rd alternative, despite my advice against it, then here is how you do it:
var app = angular.module('app', []);
app.directive('modal', function($http, $timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
$timeout(function() {
element.paulund_modal_box();
}, 0, false);
}
};
});
Usage:
<div modal></div>
Some explanation is needed here.
Why is the $timeout service necessary? jQuery plugins often require the DOM to be fully loaded in order to work properly. That is why most jQuery plugins are wrapped inside of a $(document).ready block. In AngularJS there is no concept of DOM ready, and there is no easy way in AngularJS to hook into the event. However, there is a well-known hack, which is to use the $timeout service. In Angular there are three phases:
1. compile - Angular walks the DOM tree looking for directives
2. Link - Angular calls the link function for each directive to setup watch handlers.
3. Render - Angular updates the views
Using $timeout within the Link function queues the $timeout function to be executed until after the current closure is done executing. It just so happens that the Render phase is within the current closure's scope of execution. Hence, the $timeout function will execute after the render phase, when the DOM has been loaded.
Mixing JQuery and Angular in that way is maybe a little messy, but sometimes you do want to use a well-built component. You could try to find a similar modal in Angular - angular-modal - or you could try and build the component into your Angular directive itself - jQuery Plugins in AngularJS

AngularJS 1.2 ngInclude inside ngIf

I'm running into some odd behavior when putting an ngInclude inside an ngIf or ngSwitch.
For example, take the following:
<button ng-click="showIncTemplate = !showIncTemplate">Toggle Included Template</button>
<button ng-click="showInlineTemplate = !showInlineTemplate">Toggle Inline Template</button>
<div ng-if="showIncTemplate">
<p>Included template:</p>
<div ng-include="'template.html'"></div>
</div>
<div ng-if="showInlineTemplate">
<h1>Inline Template</h1>
</div>
(http://plnkr.co/edit/gULbwnKb0gQS8DWz0V6U)
The buttons toggle an options to render the divs that follow. The inline example behaves as expected, with the content appearing or disappearing on click.
The div with the child include seems not to include the template when first drawn, but then includes it repeatedly on every subsequent redraw.
What's going on here? I do see some breaking changes around ngInclude, is there some other way I should be doing this? Or is this a bug in Angular?
Edit:
It looks like this is already in the angularjs github issue tracker:
https://github.com/angular/angular.js/issues/3627
They've fixed it in this snapshot:
http://code.angularjs.org/snapshot/

AngularJS dynamically set param of ngInclude based on route

I'm trying to dynamically include a template into my index.html. The general structure of index.html is:
<body>
<header ng-controller="Main">
<section>
<!-- global stuff -->
</section>
<section ng-include="moduleName + '/views/menubar.html'">
<!-- module-based stuff -->
</section>
</header>
<div id="view" ng-view></div>
</body>
Sample URL
example.com/<app_name>/index.html#/<module_name>[/method_name]
I can't figure out how to update $scope.moduleName when the route changes. My trouble is two-fold:
The header's controller is Main, not the controller associated with the view, so I can't? update $scope.moduleName from the view's controller (because Main and the view's controller are siblings).
In Main, I tried setting a $scope.$on('$routeChangeSuccess',…), but apparently it is not notified of route changes.
I've thought of setting up a $rootScope.$on listener (as described in SO#15355346) for the route change and broadcasting down to children, who then emit back up their route, which is broadcasted back down so it is available to Main. But that seems heinous.
And I would really prefer to keep the header outside of ng-view.
EDIT I noticed that $route.current.scope has an object named with module_name (possibly because the name of the controller associated with the route's module_name is the same). I'm wondering if I might be able to somehow use the name of that object…
It's hard to say what's wrong in your code without the full picture. Things you show look fine to me.
Please see this plunk I've created to display the ability to do it. Take note that you also can extend route objects with custom properties, like moduleName here:
$routeProvider.when('/page1', {
template: 'one',
controller: 'one',
moduleName: 'firstModule'
});

Categories

Resources