How to use nanoScroller with angular js - javascript

I have a problem with nanoScroller. I am using Angularjs on the porject.I've a directive where I want to call the nanoScroller. It looks like this:
<a ng-click='show-me'>Show Me</a>
<div class='nano' ng-show='show-me' style='height:100px'>
<ol class='nano-content'>
<li ng-repeat='post in posts'>
{{post.title}}
</li>
</ol>
</div>
I need that .nano element has the scroller. When I press show-me, div opens which has a height of 100px. I also make a call of nanoScroller in this directive: angular.element(".nano").nanoScroller()
But scroll doesn't appear.
Maybe this is related to the fact that nano elements are not present on the page yet and nanoScroller is already called for it?
I tried to use nanoScroller directive but I get the following bug with it: when changing the height of the div with "This is item" content, scroll of the whole page moves up. This can be replicated by scrolling the page to the bottom and pressing Add item button several times.
Please help.
Thanks.

You're going to have to call .nanoScroller() when you know the element is visible. I recommend wrapping it in a timeout so it will update when the DOM is updated, by adding the following to your Angular Controller methods that handle changes to posts (i.e. getPosts(), addPost(), etc)..
// refresh nanoscroller
setTimeout(function() {
$(".nano").nanoScroller();
}, 250);
In your case, you'll also need to add it to your show-me method, unless show-me is a simple boolean, in which case you'll need to pop the setTimeout() into a $scope.$watch() block that watches for changes to show-me, something like this (again, in your Controller)..
$scope.$watch('show-me', function(newValue, oldValue) {
if (newValue === true) {
// refresh nanoscroller
setTimeout(function() {
$(".nano").nanoScroller();
}, 250);
}
});

Here's a Wrapper for nanoScrollerJS with AngularJS lifecycle integration.
https://github.com/maxaon/angular-nanoscroller
DEMO PLUNKER

Related

finding the div height always return zero jquery

I am using jquery to find div's height, but it always returns zero. I can clearly see the height of the div in chrome's inspect element css window.
<div class="findheight">some text here</div>//original height is 21px
But when i do the following it returns zero:
$('.findheight').height() //it always returns zero. really making me sick
So I thought div might not have text when i call height method on it and i did like below.
if($('.findheight').text().length > 6){
alert($('.findheight').height());//This also returns zero so weird
}
I also tried by setting windows.timeoutcall, but that does not help with any delay time.
Can any one help me why I am always getting zero?
If the content of your divs are loaded dynamically, then you will need to use window.load event to get its correct height as discussed here: https://stackoverflow.com/a/13071846/1845408
$(window).load(function() {
alert($('.findheight').height());
});
Copied your code into jsfiddle, the height is 18
<div class="findheight">some text here</div>//original height is 21px
alert($('.findheight').height());
Did you wrap your jquery in a function that executes when the dom is ready?
$(document).ready(function(){
console.log($('.findheight').height());
});
It works for me otherwise your error may be browser specific.
Here is a jsfiddle of it working. Just check your console.
https://jsfiddle.net/lesshardtofind/vzxd4t57/
If for some reason you wouldn't have access to the element on document ready, such as working in dynamically templated frameworks like Meteor, Ember, React, or Angular then each object has a hook to register your functions in.
If otherwise you were trying to get access to an element in between transitions you could set a interval.
var interval;
var timeout = setTimeout(function(){
clearInterval(interval)
}, 10000); // destroy interval after 10 seconds to prevent memory leak
interval = setInterval(function(){
if($('.findheight').length > 0){
// execute your code here because you know this element is in the dom
clearInterval(interval);
clearTimeout(timeout);
// clear both timeout and interval
}
}, 100); // loop every 100 milliseconds to "poll" for the node in the dom
Try doing this:
$('div.findheight').height();
The .height() takes exactly CSS's height property.
If it's a dynamic content you have to handle this in the respective event..
For example:
If you're working with the content on page load like #renakre said, use $(window).load() or $(document).load() to trigger the call.
If it's a content generated from some other process you have coded, you have to bind respective event.. let's presume it's a click or on:
$(document).load(function() {
// Shows the height on page load
console.log($('.findheight').height());
$('#another-element-ID').click(function() {
// .. code which populate the div dynamicaly
// Shows the height
console.log($('.findheight').height());
});
$('.another-element-class').on('change', function() {
// .. code which populate the div dynamicaly
// Shows the height
console.log($('.findheight').height());
});
});
Hope this can help you.
This happens when an explicit height/width is not set for that element OR when the CSS for inner/outer elements set the height/width to 0;
To get height/width like this you have to explicitly set height/width.

Angularjs - Resize bootstrap modal after modal is shown

I am still fairly new to angularjs and am currently porting a existing spa javascript application to the angularjs framework. I am using the ui-bootstrap directive for creating bootstrap modals. I am trying to re-position the modal in the middle of the screen once the modal is displayed on the screen. With jQuery that was a easy task, just grab the modal element after calling:
$('#modal').modal('show')
But I can't seem to figure out the correct way to do this using angular. My first thought was to catch bootstrap events. But it turns out those are not fired according to
Here
and
Here
I tried creating a custom directive, but in the link function the element was defined but was not visible on the screen yet. I need a way to trigger some resize code once the modal is visible.
I also tried accessing the $modalStack.getTop(), but I end up having the same issue. There is no way to know when $modalStack.getTop().value.modalDomEl is actually resolved and showing on the screen.
I also tried the following, but the opened promise is resolved before the modal is actually showing on the screen.
modalInstance.opened.then(function(t){
//$modalStack.getTop()
});
How do you accomplish this using angular?
So I ended up taking what #user2943490 recommended and tweaked it a little bit for my use case.
I created a directive that I added to the Modal Template. Inside I check every 100ms to see if the modal-content class exists. If the class exists we know that the modal has bee added to the DOM. Once I perform my logic, I cancel the $interval check.
return {
link: function(scope, element, attrs){
var checkInterval = $interval(checkDOM, 100);
function checkDOM(){
var $content = element.find('.modal-content');
if($content.length){
//We know if $content.length > 0 Then the modal-content class exists on the screen.
$interval.cancel(checkInterval);
}
}
element.on('$destroy', function(){
$interval.cancel(checkInterval);
});
You should use CSS to position the modal as a first option. This avoids all issues around the timing of when specific elements get rendered and stays in line with Angular's spirit of using data binding rather than manual DOM manipulation to build your UI.
You won't find many things in the Angular world that give you an "element rendered" event or similar. It's just not the recommended way to do things.
If you absolutely cannot use CSS, then use a $timeout within the opened promise, and wait a short time (50ms is probably fine) before executing your repositioning logic.
modalInstance.opened.then(function(t){
$timeout(function () {
// reposition it
}, 50);
});
You should have used modal.rendered instead of modal.opened. No need for a link function or interval checks or anything else.
modalInstance.rendered.then(function () {
$('.modal-content').css({ 'width': $(document).width() - 100 + 'px' });
});

How to change content of a bootstrap popover that has already been displayed?

I have a form with a password entered twice. I check password complexity and consistency and display appropriate error messages into a popover attached to the INPUT field:
<a href="#" id="aIdPwd2" data-toggle="manual" data-content="The password entered does not match the one previously entered" data-placement="right" href="#" rel="popover">
<input type="password" id="iIdPwd2" class="fmt1" size="60" value=""/>
</a>
With this code:
$("#aIdPwd2").popover({content: msg});
You can chose dynamicaly the message that will be displayed. But once it has been displayed once, it will then always remain the same.
I read many articles about this popular issue and did try many things (attach 2 different popover to the same input, change the inner html in the getElementsByClassName("popover-content"), destroy and recreate the popover, ..), but without any success so far.
A solution on how to change content of a bootstrap popover that has already been displayed or any kind of work-around would be highly appreciated.
In Twitter Bootstrap 3, I just update the content and then call show. Calling of the show ensure that its resized correctly and then positioned correctly.
$(".notes").data("bs.popover").options.content="Content1";
$(".notes").popover("show");
$(".notes").data("bs.popover").options.content="Content2";
$(".notes").popover("show");
If you are using data tags to show the content then you will need to update the data tag as that takes precedence. eg.
$(".notes").attr("data-content","Content1");
$(".notes").popover("show");
$(".notes").attr("data-content","Content2");
$(".notes").popover("show");
I like the second option better coz it doesn;t access the internals by doing data(bs.popover) but the first options is much faster as it doesn't update the dom. So pick what floats your boat.
document.getElementsByClassName("popover-content")[0].innerHTML = 'something else';
sure that this doesn't work?
tried it on this page and it works as expected.
UPDATE: it will work only if the popover is visible because the element is recreated/destroyed every mouseover/mouseout event
i guess it's not the best solution, but you can do this:
var msg = 'ben123 is not a goddamn password!';
document.getElementById('password').addEventListener('mouseover', function() {
document.getElementsByClassName("popover-content")[0].innerHTML = msg;
});
and change msg when you need
The problem with solutions that rely on popover('show') is that if you do this in an event handler for the show event, you will end up with an infinite loop.
If you just want to display some content in your popover when it has already been shown, you will need to directly modify the DOM:
$("#aIdPwd2").next(".popover").find(".popover-content").html(msg);
For example, if you want a popover that will load some data from an API and display that in the popover's content on hover:
DOM:
Hover here for details
jQuery:
$("#myPopover").popover({
trigger: 'hover'
}).on('shown.bs.popover', function () {
var popover = $(this);
var contentEl = popover.next(".popover").find(".popover-content");
// Show spinner while waiting for data to be fetched
contentEl.html("<i class='fa fa-spinner fa-pulse fa-2x fa-fw'></i>");
var myParameter = popover.data('api-parameter');
$.getJSON("http://api.example.com", {
'apiParameter': myParameter
}).done(function (data) {
var result = data['apiReturnValue'];
contentEl.html(result);
}).fail(function (data) {
result = "No info found.";
contentEl.html(result);
});
});
This, of course, assumes that you trust the data supplied by api.example.com. If not, you will probably want to escape the data returned to mitigate XSS attacks.
To replace the contents of a popover on an element, first call destroy.
Tested on Bootstrap 3.1.1
$("#aIdPwd2").popover('destroy').popover({content: msg});

Infinite Scroll + Swipe.js

Background:
I'm making a portfolio site utilising both Swipe.js and Infinite Ajax Scroll (JQ).
Problem:
When the content from extra pages is loaded into the current page, it is not processed by the already-loaded Swipe.js script. This means that the new content doesn't have it's mark-up changed (needed for the swipe functionality to work).
I think I need to get the Swipe.js script to fire after each page re-load. Would that fix it? Please explain this to me like I'm an 8yr old. JS is not a strong suit...
Demo:
http://hatchcreative.co.nz/tomo
You can see that as the page loads new content, the buttons on either side of the sliders no longer work.
Yes you're right, after the images are loaded you have to create a new Swipe instance on these new elements (as they weren't there at the beginning, when the page was loaded).
Based on the docs of infinite scroll you can use onRenderComplete.
So you had your jQuery.ias constructor like this:
jQuery.ias({
// ... your settings...
onRenderComplete: function(items) {
$(items).each(function(index, element) {
new Swipe(element);
});
}
});
This should work this way somehow, but I am not exactly sure; I haven't worked with these libraries yet.
Edit:
After some more inspection of your code, I saw you had some inline click handler like: onclick='two.prev();return false;'.
You need to remove this and add your onclick handle in the same onRenderComplete function.
onRenderComplete: function(items) {
var swipe;
$(items).each(function(index, element) {
swipe = new Swipe(element);
});
// find tags with the class 'forward' inside the current element and add the handler
$(element).find('.forward').on('click', function() {
swipe.next();
});
// ... also for previous
}
By the way: Usually you should provide a jsFiddle with your important code parts, so it's easier for us to get the problem, and the question is not getting obsolote when the linked page changes.

jQuery: how to implement this roll-out effect?

I need some help to implement this roll over / out effect.
This is the screenshot: http://dl.dropbox.com/u/72686/roll-over-out.png
I have a menu. When I roll over the item "Products" the popup block appears below it, with a tree with all products.
<div id="menu">
<div id="product"> Roll over here </div>
...
</div>
<div id="popup">
<div> <a> link </a> </div>
<div> <a> link </a> </div>
<div> <a> link </a> </div>
...
</div>
This block has css:
#popup {
position:fixed
display:none
}
Now, it is clear how to implement roll over to show the block:
("#product").mouseover(function() {
$('#popup').css("display","block");
})
However how can I handle the rollout ? I have the following issues:
1) If I add roll-out to the menu item "#product", when I roll-out from it (to move to the popup with product trees), I make this last one to disappear (because I'm leaving the menu item).
2) If I add roll out functionality to the popup, I have issues with his children. i.e. If I move the mouse over a link of the tree, the popup disappear (because I'm leaving the parent #popup).
thanks
ps. I cannot use :hover (it is not supported by jquery version on Drupal CMS).
Firstly I think you will find that mouseenter and mouseleave are better events for this kind of thing. See the jQuery example in IE to understand why, not a huge problem but you may end up wit flickering otherwise.
However that will still not solve your problem. I would suggest use a setTimeout to close the menu, and then if your mouse enters the menu before the time out cancel the time out:
var t;
$("#product").mouseleave(function() {
t = setTimeOut(function(){$('#popup').hide();}, 100);
})
$("#popup").mouseenter(function() {
if(t)
{
clearTimeout(t);
t=null;
}});
This will prevent the popup from closing if you move from the product element to the pop up element. The clear timeout method prevents the timeout function from being executed.
Thorough Tutorial: Drop down menu
I have created similar solution, you can check it out here. See the demo here.
By the way, :hover isn't jQuery - it's CSS.
http://www.w3schools.com/cssref/sel_hover.asp

Categories

Resources