Accessing the element a directive is bound to - javascript

I want to create a directive that is applied to elements to set their max height equal to the window height minus the distance from the top of the element to the top of the window.
I was trying it like this
.directive('resize', function ($window) {
return function (scope, element) {
var w = angular.element($window);
scope.getWindowDimensions = function() {
return { 'h': w.height() };
};
scope.$watch(scope.getWindowDimensions, function(newValue, oldValue) {
//get header height including margins
var headerHeight = $('.page-header').outerHeight(true);
scope.windowHeight = newValue.h;
scope.style = function() {
return {
'height': (scope.windowHeight - headerHeight) + 'px',
'max-height': (scope.windowHeight - headerHeight) + 'px'
};
};
}, true);
w.bind('resize', function() {
scope.$apply();
});
}
})
But I would have to add a var for every element that is above the element whose height I want to set. So I believe using
var scrollTop = $(window).scrollTop(),
elementOffset = $('#my-element').offset().top,
distance = (elementOffset - scrollTop);
would be better as it does all the measurements relative to the element its setting but how do I access this element from within the directive without adding any extra classes or identifiers?
Also do I need to create an isolate scope for me to use this more than once on a single page?
My goal is to basically have my web apps body element equal to the height of the window and any containing divs that are higher than that height to have scroll bars.

1)It would be better if you have isolate scope. so that the directive can be user multiple elements with different heights.
2) Send an array of elements (Which are above the required element) as an attribute to the directive. And calculate the height to be deducted from window height.

Related

Determine element is at bottom of viewport and add class to it?

need some help here. I need to determine when a certain element is at bottom position of the viewport and then to add fixed class to it. So on scroll down add class when element is at bottom 0 and remove class when i scroll back up.
$(window).scroll(function() {
var $el = $('.content-btn-row');
if ($($el).position().top + $($el).height()) {
console.log("bottom!");
$(".content-btn-row").addClass("fixed");
} else {
$(".scontent-btn-row").removeClass("fixed");
}
});
IMO we should take into account inner height of a window's content area (it can be different that window height) and check if document has been scrolled.
window.innerHeight - returns the inner height of a window's content area
window.pageYOffset - returns the pixels the current document has been scrolled (vertically) from the upper left corner of the window
If the element is below viewport at the beginning this code should be ok:
var elem = window.innerHeight + $($el).height(); //position of the element
var winScroll = window.innerHeight + window.pageYOffset; //viewport height + scroll
if (elem) >= (winScroll) {
console.log("bottom!");
$(".content-btn-row").addClass("fixed");
} else {
$(".scontent-btn-row").removeClass("fixed");
}
}
and it will be better to check if there is a class "fixed" with hasClass before we add or remove it.
Why are you comparing the variables by adding same constant values(window.innerHeight) to them?
var elem = $($el).height();
var winScroll = window.pageYOffset;
if (elem) >= (winScroll) {
console.log("bottom!");
$(".content-btn-row").addClass("fixed");
} else {
$(".scontent-btn-row").removeClass("fixed");
}}
By this way we can reduce some complexity and code

Add class after scroll on variable height div

Can someone spot the mistake in my JS syntax?
function setSize() {
var headerHeight = $('#header-blue:visible').height();
var subHeight = $('.subhead:visible').height();
var totalHeight = headerHeight + subHeight;
console.log(totalHeight);
}
// Set height variables on load
$(document).ready(function () {
setSize();
});
// Set height variables on window resize
$(window).resize(totalHeight);
// Fixed header on scroll
$(function() {
var header = $(".subhead");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= totalHeight) {
header.addClass(" fixed");
} else {
header.removeClass("fixed");
}
});
});
The goal here is to set a class when a scroll position is reached. The scroll position is variable because it depends on the height of 2 div's, which changes on mobile and desktop.
Unfortunately, I am receiving syntax errors saying totalHeight is not defined.
The variable totalHeight is only in the scope of the function setSize(), therefore it cannot be used outside the function. To solve the problem you have to make the variable global such as declaring it before the function:
var totalHeight;
function setSize()
You can also do the following:
var totalHeight = function(){
//code of the function here and make it return the value
}

Jquery Position not honoring on first call

I am trying to make my autocomplete menu open above the input box if there is not enough space below the input box to display the menu. The code works fine except for on the initial render.
This means that it always displays at the bottom when:
1. Start searching
2. Click in the field and fire the search for the existing text in field
I have it output the position.my and position.at contents and they both are correct for "above" placement but it still displays below the input box.
I have the function called resize that is binded to window scroll and resize also. The moment you scroll the page, the menu gets positioned correctly. My suspect is that it is positioning before fully rendering.
Code
_renderMenu function hook
// Autocomplete _renderMenu function
$(autocomplete_object)._renderMenu = function( ul, item ) {
var that = this;
jQuery.each( items, function( index, item ) {
that._renderItemData( ul, item );
});
// Make sure the menu is now shown to calculate heights and etc (menu is now rendered, position rendering next)
jQuery(ul).show();
autocomplete.resize(ul, options);
autocomplete.create_dropdown_handlers(ul, options);
}
Resize Function
// Resize function
function resize( ul, options ) {
var height;
// If the height of the results is smaller than the space available, set the height to the results height
var ul_height = 0;
jQuery(ul).find('li').each(function(i, element){
ul_height += jQuery(element).height();
});
// Make the height the full height available below the input box but above the window cut off
// Move the dropdown above the input box if there is not enough room below the input box
var $parent = jQuery("#" + options.name);
var padding = 25; // arbitrary number to prevent dropdown from hitting the window border in either direction
var bottom_distance = autocomplete.getViewportHeight() - ($parent.offset().top + $parent.height()) - padding;
var bottom_limit = 200;
var ul_position = {
my: "left top",
at : "left bottom",
of: $parent,
collision: 'none'
};
height = bottom_distance;
if (bottom_distance < bottom_limit) {
var top_distance = $parent.offset().top - padding;
height = top_distance;
// ----- It is getting here fine! -----
ul_position.my = "left bottom";
ul_position.at = "left top";
}
// We have room to show the entire dropdown results without a scrollbar
if (ul_height < height) {
height = 'auto';
}
// Position below or above parent depending on space
jQuery(ul).position(ul_position);
jQuery(ul).css({height: height == 'auto' ? height : height + 'px'});
}
TLDR:
Jquery position is set to show above input field, but it still shows below?
I ended up having to update the autocomplete object's position value as well as the ul position. I believe the issue was that the initial render would inherit the autocomplete's position variable (Which defaults to showing below the input box).
Here is the new line:
// In the resize function after jQuery(ul).position(ul_position);
$parent.autocomplete("option", "position", ul_position); // Now the rendering is correct!
Resize function addition
function resize (ul, options) {
...
calculate the height and position requirements
...
jQuery(ul).position(ul_position);
$parent.autocomplete("option", "position", ul_position); // <-- Addition to honor position for rendering
}

Dynamically set element height and width

I'm using Backbone to render a square tile element in which I set the height and then dynamically set the width to match the height. However, when trying to fetch the elements height, I get 0 returned.
Here is my code:
var app = app || {};
app.ClassModelView = Backbone.View.extend({
className: 'tile',
template: _.template('<%= name %>'),
render: function() {
var dim = 'calc(' + parseInt(100 / app.global.rows) + '% - ' + app.global.margin * (app.global.rows + 1) + 'px)'; //e.g. "30% - 20px"
this.$el.append(this.template(this.model.attributes)).css({
margin: app.global.margin + 'px',
height: dim,
}).css({
width: this.$el.height() + 'px',
});
return this;
}
})
How would I set the width of $el to the height? I'm not sure if I'm doing something syntactically wrong or if it is the way I'm using Backbone that is resulting in my problem.
I've ran into similar issues in the past. In most cases, it was because my view had rendered but had not yet been inserted into the DOM. This is pretty common when dealing with nested views.
You can test for this by setting a break point in your onRender method and checking this.$el.parent(). You might want to go up a few parents to make sure the parent elements are in the DOM.
You can get around this by binding to the DOMNodeInserted event:
this.$el.on('DOMNodeInserted', function(e) { console.log($(e.target).outerHeight()); })

jQuery - UI Resizable Resize All Child Elements And Its Font-Size

I have been searching the answer for this problem for 1 day, but haven't find it yet!
I want to resize all child elements by calculating and comparing their parent's size with them when their parent is resized and then apply the width and height to every children.
I have writing some lines of codes but this seem not working as expected. The children sizes gone wild with this way:
$('.parentElement').resizable({
resize: function(e, ui) {
var thisw = $(this).outerWidth();
var thish = $(this).outerHeight();
$(this).find("*").each(function(i, elm){
elw = $(elm).outerWidth();
elh = $(elm).outerHeight();
wr = parseFloat(elw) / parseFloat(thisw);
hr = parseFloat(elh) / parseFloat(thish);
w = elw * wr;
h = elh * hr;
$(elm).css({"width": w, "height": h});
});
},
});
Maybe someone can help me to correct my codes above so the resizing of child elements going smoothly!
EDIT:
Here is a fiddle demo.
You can see it that by my code above, the children sizes going wild while I want them to resize smoothly fit with their parent size.
I know I can set the children element's width and height by percentage through jquery or css, but I don't want to do it that way, because text's size cannot be resized to fit container's size by percentage!
The reason why your current code does not achieve your intention of keeping children (and their font size) relatively sized to their parent is that you have no measurement of the original child and parent dimensions/ratios, so you cannot calculate how much their dimensions have changed (and by extension how much you need to change the child dimensions/font size).
One way to avail this information for calculations is to store them in data attributes before any resizing has occurred:
// Storing initial parent CSS
$('.parentElement').each(function(){
$(this).data("height", $(this).outerHeight());
$(this).data("width", $(this).outerWidth());
});
// Storing initial children CSS
$('.parentElement *').each(function(){
$(this).data("height", $(this).outerHeight());
$(this).data("width", $(this).outerWidth());
$(this).data("fontSize", parseInt($(this).css("font-size")));
});
$('.parentElement').resizable({
resize: function (e, ui) {
var wr = $(this).outerWidth()/$(this).data("width");
var hr = $(this).outerHeight()/$(this).data("height");
$(this).find("*").each(function (i, elm) {
var w = $(elm).data("width") * wr;
var h = $(elm).data("height") * hr;
// Adjusting font size according to smallest ratio
var f = $(elm).data("fontSize") * ((hr > wr) ? wr : hr);
$(elm).css({
"width": w,
"height": h,
"font-size": f
});
});
},
});
Now, with each resize of a .parentElement, the ratios of its present versus original dimensions are calculated, then multiplied with the dimensions and font size of its children.
Here's a JSFiddle to demonstrate. Hope this helps! Let me know if you have any questions.

Categories