Angular.js Client height - javascript

I have an angular.j app, which has a view and a directive. The various views used have different client height. I am trying to place a default background on the view, while various views have different page heights.
To place a background on the screen, I need to know the client window height, which is the minimum height that the background will be set to. The height of the view, if this is bigger than the client height, the background would need expanding to cover the extra height.
The view:
index.html
<body ng-app="myApp">
<div main-container></div>
<script src=......></script>
</body>
The view controller
js/app.js
var myApp = angular.module('myApp', ['ngRoute']);
myApp
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html'
})
.otherwise({redirectTo: '/'
});
}]);
The Home view
views/home.html
<div style="height: 2000px">
<p>Home View content</p>
</div>
The view directive for main-container
js/directives/main.js
myApp.directive('mainContainer', ['$window', function($window) {
return {
link: function(scope, elem, attrs) {
scope.onResize = function() {
var header = document.getElementsByClassName('main-container')[0];
elem.windowHeight = $window.innerHeight - header.clientHeight - 80;
$(elem).height(elem.windowHeight);
}
scope.onResize();
angular.element($window).bind('resize', function() {
scope.onResize();
})
}}
}])
The view directive does not get the height of the view, it gets the client window height when ever the page is re-sized & refreshed. I would like to also get the view height, so that I can set the height of the container background to either the client height or view height, which ever is the bigger.
I'd like to do is get the height of the view, as set in the home.html css, is there a way to do this?
Please assist.

I'd suggest you to put you directive attribute on ng-view element, also your directive needs some changes. In order call calculation function for height scope.onResize you need to call it on element.on('load') also will ensure that the every time view changes will call scope.onResize function.
Directive
myApp.directive('mainContainer', ['$window', function($window) {
return {
link: function(scope, elem, attrs) {
scope.onResize = function() {
var header = document.getElementsByClassName('main-container')[0];
elem.windowHeight = $window.innerHeight - header.clientHeight - 80;
$(elem).height(elem.windowHeight);
}
scope.onResize();
angular.element($window).bind('resize', scope.onResize);
//below function will call on view change in ng-view
element.on('load', function(){
$scope.$apply(scope.onResize);
})
}}
}])

Related

Angular custom directives not working with external javascript plugin

I am creating a custom angular directive that will use the Image Tilt Effect plugin.
<tilt></tilt>
the template looks like this.
<li class="grid__item">
<div class="grid__img grid__img--example-1" >
<img src="img/3.jpg" class="tilt-effect" alt="grid01" data-tilt-options='{ "opacity" : 0.3, "extraImgs" : 3, "movement": { "perspective" : 1200, "translateX" : -5, "translateY" : -5, "rotateX" : -5, "rotateY" : -5 } }' />
</div>
The problem I have is this script that I am loading at the bottom of the page doesnt seem to be on when the custom directive is injected into the page.
<script src="js/tiltfx.js"></script>
If I try and move the script into the html fragment for the custom directive I get an Error: $compile:tplrt
I've created a wrapper directive for this the Image Tilt Effect plugin (fiddle).
When you have a DOM plugin you need to use in angular, don't use auto initialization, such as the data-tilt-options of this plugin, because they are hard to predict, and may cause weird behavior, memory leaks, etc... This plugin has a manual init method - new TiltFx(element, options), so we can use that.
Another problem is that this plugin must wait for angular to finish rendering, before it should be initialized. The simple fix is just using setTimeout or $timeout (if we need to update the digest cycle), to put the init at the end of the JS queue. We can also use mutation observers to do that, but that's out of this answer's scope.
One troubling aspect of using a DOM plugin in angular, is memory leaks. Plugins should have some sort of a cleaning mechanism. This plugin doesn't. So, you'll have to check for memory leaks, and if there are stray event handlers remove them, when the wrapped element is removed.
Directive code:
appModule.directive('tilt', function tilt() {
var ddo = {
template: '<div class="grid__img"><img class="tilt-effect" ng-src="{{imgSrc}}" alt="The image" />',
restrict: 'E',
replace: true,
scope: {
imgSrc: '#', // the image src
tiltOptions: '=?' // the tilt options object - optional
},
link: function (scope, $el) {
var img = $el[0].querySelector('img.tilt-effect'); // find the img element
var tilt;
setTimeout(function () { // wait 'till directive is rendered
tilt = new TiltFx(img, scope.tiltOptions); // apply tilt on image with options (if any)
});
$el.on('$destroy', function() {
// use tilt variable to perform cleanup on wrapper and img if needed
tilt = null;
});
}
};
return ddo;
});
Usage:
<div ng-app="tilt">
<tilt img-src="http://cdn.cutestpaw.com/wp-content/uploads/2013/12/Most-Famous-Felines-034.jpg" tilt-options='{ "opacity" : 0.3, "extraImgs" : 3, "movement": { "perspective" : 1500, "translateX" : -5, "translateY" : -5, "rotateX" : -5, "rotateY" : -5 } }'></tilt>
<tilt img-src="http://www.cats.org.uk/uploads/images/pages/photo_latest14.jpg"></tilt>
</div>
Don't forget that this plugin requires the container to have fixed width and height, for example:
.grid__img {
width: 400px;
height: 400px;
}
Change
<script src="js/tiltfx.js"></script>
to
<script ng-src="js/tiltfx.js"></script>

How to get the svg element's changing width/height in an angular Directive?

I have a directive as below, where I defined a d3 svg attribute's width of 100%. I need to get the value of back in px. I was able to access the SVGLength object using console.log((svg[0])[0].width.baseVal).
But whenever the value changes, the object is getting updated but, when I print console.log((svg[0])[0].width.baseVal.value) - I always get 0.
Is there a way, i can add a watch on the element's baseVal?
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
angular.module('sortron.directives').directive('myDirective', function () {
return {
restrict: 'EA',
scope: {data: "="},
replace: true,
template: '<svg id="chart"></svg>',
link: function (scope, element, attrs) {
var checkForNewVal = function (newVal, oldVal) {
var svg = d3.select("#chart");
svg.selectAll('*').remove();
var bar = svg.attr("width", "100%")
.attr("height", "100%")
.selectAll("svg")
.data(newVal)
.enter();
console.log((svg[0])[0].width.baseVal);
};
// Add watch on the data
scope.$watch('data', checkForNewVal,true);
}
}
});
Also, I see

How to get elements height of an element dynamically loaded inside an ionicdialog

I have a modal dialog based on a template in which i load a GoogleMap.
I want the GoogleMap to take the remaining Space below a header and a sub-header included in the template.
-- header -- (height is defined through mediaqueries in css)
-- subheader -- (height is defined through mediaqueries in css)
-- remaining space inside dialog --
This is my controller so far:
$scope.creategooglemapsmodal = function() {
$scope.item.showmap = true;
$ionicModal.fromTemplateUrl('templates/Gmapdialog.html', {
scope: $scope,
animation: 'slide-in-up'
})
.then(function (modal) {
$scope.googlemapsmodal = modal;
$scope.googlemapsmodal.show()
.then(function() {
// after showing the modal i would like to adjust the mapcontainers height - before i initiate the map, which will call the containers height.
$scope.showmapinit();
$scope.modalhiddenlistener = $scope.$on('modal.hidden', function() {
$scope.hidegooglemapsmodal();
});
});
});
};
What is the recommended way to handle this?
I've found a solution:
after initialization of the GoogleMap i call
map.fitBounds(bounds);
to set Zoom and Center (after placing markers)
And right after that i call:
$scope.googlemapsmodal.$el.find('.angular-google-map-container').addClass('expander');
The CSS looks like this:
.expander {
position:inherit !important;
-webkit-transform: none !important;
}
Hope this will help someone

Resizing divs on window resize using AngularJS

I'm trying to use a directive to resize a few divs on my page (5 to be exact). They're all columns which I'd like to resize so they always stretch to the bottom of the window.
I used this as a guide: Window resize directive
Coming up with this:
app.directive('resize', ['$window', function($window) {
return {
link: function(scope, elem, attrs) {
scope.onResize = function() {
var padding = 30,
offset = elem.prop('offsetTop'),
height = $window.innerHeight - offset - padding;
elem.css({height: height + 'px'});
}
scope.onResize();
angular.element($window).bind('resize', function() {
scope.onResize();
})
}
}
}]);
I've given my divs the directive element identifier of "resize".
On load, it works great - all divs are correctly sized. But, on changing window size, only the last rendered div is resized. I'm guessing it's because the resize window event is being overwritten each time with the scope of each div in turn, and so by the time the page is loaded, the window resize event only refers to the last rendered div.
How would I go about it so the resize event applies to all divs and not just the last one?
While looking into a completely unrelated issue, I realised I just needed to set the scope:
app.directive('resize', ['$window', function($window) {
return {
scope: {},
link: function(scope, elem, attrs) {
....
}
}
}]);

How can I trigger resize event in AngularJS

I'm using Angular & Bootstrap, with the nav tab control to switch visibility of divs. In one div, I have a large img (CAD drawing of building). I also then overlay markers on the image. I want to scale the x/y position of the markers based on the image width & image naturalWidth. I'm using a resize directive to detect changes and update my scope.
My problem is that if user switches tabs and switches back to the div with the CAD img, the refresh doesn't happen until I resize the browser (or surprisingly if I press the CMD key on Mac).
Is there an angular way to trigger the resize event to force my markers to be recalculated. Or is there an event I can tap into that is fired when the is fully displayed ?
Or is there a more refined angular approach I should take?
This is the HTML, the resize directive I've written is on the tag.
<div id="imageDiv" style="position: relative;" ng-show="selectedLocation" >
<img ng-src="../maps/image/{{selectedLocation}}"
style=" max-width: 100%; max-height: auto; border:solid 1px black" resize imageonload />
</div>
And this is the resize directive (adapted from http://jsfiddle.net/jaredwilli/SfJ8c/)
directive('resize', function($window) {
return function(scope, element) {
var w = angular.element($window);
scope.imgCadImage = element;
scope.getWindowDimensions = function() {
return {
'h' : scope.imgCadImage[0].width,
'w' : scope.imgCadImage[0].height
};
};
scope.$watch(scope.getWindowDimensions, function(newValue, oldValue) {
if (scope.imgCadImage[0].naturalWidth)
scope.imgScale = newValue.w / scope.imgCadImage[0].naturalWidth;
else
scope.imgScale = 1;
console.log("watched resize event - scale = "+scope.imgScale)
scope.updateCADMarkersAfterResize();
}, true);
w.bind('resize', function() {
console.log("'resize' - scale = "+scope.imgScale)
scope.$apply();
});
};
}).
This worked for me when the above did not.
$timeout(function() {
$window.dispatchEvent(new Event("resize"));
}, 100);
I had to also use $timeout with a delay in my case to prevent errors about digest cycles already being in progress. Not all uses cases may need this.
dispatchEvent is well supported http://caniuse.com/#feat=dispatchevent
However, it you need IE9 and IE10 support you'll have to use their propritary method: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/fireEvent
Try injecting $timeout into the resize directive:
directive('resize', function($window, $timeout) {
... then add the following line to the bottom of it:
$timeout(function(){ w.triggerHandler('resize') });
This should trigger the handler you have bound to $window.resize just after the browser renders.
The accepted answer did not work for me - w is undefined.
This did:
$timeout(function(){
$(window).trigger('resize');
});

Categories