I am trying to watch the width of a directive's element (the directive itself). In the demo below I set the element style to 100%, in the real world app the element resizes through media queries.
Here is my approach:
http://jsfiddle.net/fusio/5zgaj79b/
scope.$watch(
function() {
return element.width()
},
function(val) {
console.log(val)
},
true
);
Is .width() not changing?
The reason it is not triggering is that, for the first function to get called, a digest cycle has to be triggered. How to do it? Try adding the following to your fiddle:
angular.module('HelloApp', ['components']).run(function($rootScope) {
$(window).on("resize", function() {
$rootScope.$apply();
});
});
For a real scenario, you may want to limit the scope of the $apply to a specific scope, so as not to cause unnecessary watcher invocations.
Related
I am trying to create a loading spinner to put at the bottom of a div like this jsfiddle so its always at the bottom when my returned code is appended to its sibling above its child element. Then when I scroll to the bottom of the page my endless scroll script runs and changes display from none to block of the spinner and once the next set of results is appended the spinner is hidden again.
The problem is is that once the scrollbar hits the bottom of the page the spinner triggers the get request twice for some reason and my results are doubled upon being appended. This happens only when the spinner div is inside the container element. My code runs fine with the spinner there appending the results once. Even using position:relative; on the container and absolute on the spinner div and setting bottom:0px; causes two get requests.
No matter how I create the spinners with CSS they all do the same thing multiple get requests. I have had to place the spinner in a div with overflow:hidden; also to prevent the jumping behavior of the scrollbar which causes continuous get requests when my code triggers.
Am I going the right way about this or is my logic flawed or what is wrong here?
EDIT js code that triggers the get request
$(document).ready(function() {
if ($('.pagination').length) {
$('#id2').scroll(function() {
var currentuserfeed = $('#currentuserfeed .pagination .next_page').attr('href');
if (currentusershow && $('#id2')[0].scrollHeight > 820 && $('#id2').scrollTop () >= $('#id2')[0].scrollHeight - $('#id2').height ()) {
return $.ajax({
type: 'GET',
url: currentusershow,
data: { currentusershow: 'user' },
dataType: 'script',
});
};
});
return $('#id2').scroll();
};
};
I have illustrated the problem in this CodePen
const Component = ({ structure }) => {
switch (structure) {
case 'nested':
return (
<div>
<AnimatedComponent />
</div>
);
case 'flat':
return
<AnimatedComponent />
;
}
};
There's some logic in AnimatedComponent that changes the styling of the Component in an animated fashion, e.g. change the background color from black to red over a duration of 1 second. The animation is started by changing a color class on AnimatedComponent. There is CSS to handle the animation given the changed class.
When changing the DOM structure from nested to flat, the HTML element is destroyed and recreated, the transition starting state is lost (aka the browser doesn't know which class was set before because the element was newly created).
What I want React to do is to change the DOM structure with moving elements in new positions, not destroying and recreating them.
Is this possible?
I tried to use the key props on <AnimatedComponent />, but it only fixes the flash of DOM change. Animation is skipped. See Codepen. Thanks Thomas Rooney for this suggestion.
Can I tell React to apply the class changes just one tick after the position of the DOM element was changed?
Can I tell React to apply the class changes just one tick after the position of the DOM element was changed?
Yes, this is precisely what the setTimeout function is for. Copying your second example, where you fixed the flickering, wrapping your color action dispatch with setTimeout (with no time value, which defaults to 0), seems to fix your issue.
onColorClick: () => {
setTimeout(() => {
dispatch({type: 'TOGGLE_COLOR'})
})
},
codepen
Update: I've noticed it's a bit more reliable to add some time before the color change (second argument in setTimeout, (fn, ms). I believe this is because setState is also happening asynchronously.
onColorClick: () => {
setTimeout(() => {
dispatch({type: 'TOGGLE_COLOR'})
}, 100) <-- play around with this value
},
so in the back of the 'discover meteor' book they explain how to do page transitions. i've got it working, however it causes problems with the loading of javascript functions and variables on other pages that its animating into. it seems they're not ready or simply don't exist at the time the page is routed.
Template.layout.onRendered(function() {
this.find('.pos-rel')._uihooks = {
insertElement: function(node, next) {
$(node).hide().insertBefore(next)
.delay(200)
.velocity("transition.slideUpIn", 1000)
},
removeElement: function(node) {
$(node).velocity({
opacity: 0,
},
{
duration: 100,
complete: function() {
$(this).remove();
}
});
}
}
});
if i remove the above code then all my javascript variables and functions work correctly. does anyone have another working solution to page transitions using velocity.js ? i did find this one but its a year old and i couldn't get it to work at all, it just makes the content where '{> yield}' is go blank :(
Just a note for asking questions on stack overflow: "causes problems with the loading of javascript functions and variables" is pretty vague. Its best to give more specifics.
But anyways, you said here that you're using isotope to render items in a grid. I'm assuming you're calling $elements.isotope() within a Template[name].onRendered callback.
This is probably the issue because its trying to compute and rearrange into a grid the elements while they're hidden. Using display: none actually removed the elements, thus isotope can't compute the sizes, etc. for the layout. Try this:
insertElement: function(node, next) {
$(node).css("opacity", 0).insertBefore(next)
.delay(200)
.velocity("transition.slideUpIn", {duration:1000, display:null})
},
opacity: 0 should do what you're looking for. It will make them transparent without removing them from the transition.slideUpIn should animate opacity so you're good there.
Also, velocity transitions mess with the display property. Setting display: null in the animation options prevents it from setting the display to block or whatever it wants to do. This may or may not be necessary, but I pretty much always use it.
You could use:
onAfterAction
onBeforeAction
. The solution should be something like this:
animateContentOut = function() {
$('#content').css('display', 'none');
this.next();
}
fadeContentIn = function() {
$('#content').velocity('transition.fadeIn',1000);
}
Router.onBeforeAction(animateContentOut)
Router.onAfterAction(fadeContentIn)
and if a link is underlined, i want it to get rid of the underline on hover. If a link has no underline, i want it to get one on hover.
Is there a smart way to do this with SASS rather than hard coding it for every link?
As others have stated, to do this within CSS or SASS this is something that requires a default style for links and a class or data attribute that must be applied to alternative links.
The type of auto-smart styling is possible with javascript though if that's an acceptable alternative. I made a quick jQuery Fiddle that would work by checking all links for the text-decoration style. This has performance drawbacks due to scanning the DOM for all links every page load. It also breaks the law of keeping styling with the CSS realm so it's up to you if it's worth it.
var links = $('a');
links.each(function (i) {
var $this = $(this);
// if this has underline
if ($this.css('text-decoration') == 'underline') {
$this.hover(
function() {
$this.css('text-decoration', 'none');
}, function() {
$this.css('text-decoration', 'underline');
});
} else {
$this.hover(
function() {
$this.css('text-decoration', 'underline');
}, function() {
$this.css('text-decoration', 'none');
});
};
});
https://jsfiddle.net/ym8s6Lwh/
I'm trying to resize a div with a background image (left) and a variable height description (right), but can't get it to work. Here's the fiddle
. I tried several things with/without zepto/jQuery/document.getElementById ... nothing works.
.directive('resize', function () {
return {
restrict: 'A',
scope: {},
link: function(scope, elem, attrs) {
elem.height(400);
}
};
})
You can use jQuery:
jQuery(elem).height(400);
Fiddle
Not too ideal though :(
If you don't use jQuery, AngularJS implements only a lite version of the framework, jqLite, which doesn't have a height() method. You can see the documentation for the list of the available functions in jqLite.
In your case, for instance, you can simply do:
element.css('height', '400px');
Fiddle
Notice that, as pointed out in the comment, your fiddle wasn't functional. I've corrected that problem.