Dragging item gets hidden when overflow-y is used - javascript

I created a Fiddle to demonstrate the problem (also can be run inside this question, below).
I have a sidebar of playing card images that I want to drag into a main area. The sidebar holds a lot of cards so I want it to be scrollable. However, when I give it a scroll feature, then when I drag a card, it gets hidden when I drag it out of the sidebar.
var app = angular.module('myApp', ['ngDraggable']);
app.controller('ctrl', function ($scope) {
});
#gallery-container {
overflow-y: scroll;
}
.card {
width: 100%;
}
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script>
<script src="https://rawgit.com/fatlinesofcode/ngDraggable/master/ngDraggable.js"></script>
<div ng-app="myApp">
<div ng-controller="ctrl">
<div class="row">
<div class="col-xs-3">
<div id="gallery-container">
<div class="row">
<div class="col-sm-12">
<img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="">
</div>
</div>
<div class="row">
<div class="col-sm-12">
<img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="">
</div>
</div>
<div class="row">
<div class="col-sm-12">
<img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="">
</div>
</div>
<div class="row">
<div class="col-sm-12">
<img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="">
</div>
</div>
<div class="row">
<div class="col-sm-12">
<img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="">
</div>
</div>
<div class="row">
<div class="col-sm-12">
<img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="">
</div>
</div>
<div class="row">
<div class="col-sm-12">
<img ng-drag="true" ng-drag-data="hi" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" class="card" src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="">
</div>
</div>
</div>
</div>
<div class="col-xs-9">
<h2> Drop Area </h2>
</div>
</div>
</div>
</div>
When I comment out overflow, like
/*overflow-y: scroll;*/
in the CSS, it now works.
How can I both have a scrolling sidebar and drag items out of it?

To drag objects between zones with scrolled or hidden overflows, you need a to create clone div between the drag div and the drop div using the ng-drag-clone
<div ng-drag-clone="">
<img ng-src="{{clonedData .link}}" width="100px">
</div>
check my Fiddle
I've tried to update your code, but quickly to demonstrate the point:
I noticed you did not create any way for the drop zone to render or store the data being passed.
I created a cards array and a cardsDrop array to store the data.
I also implemented onDropComplete function to push the card object into cardsDrop
$scope.onDropComplete = function (data, evt) {
var index = $scope.cards.indexOf(data);
if (index == -1) $scope.cardsDrop.push(data);
}
and a onDragComplete function to remove a card from the original deck (for some applications, this is optional... sometimes you want a list to drag from that does not remove options):
$scope.onDragComplete = function (data, evt) {
console.log("133", "$scope", "onDragSuccess1", "", evt);
var index = $scope.cards.indexOf(data);
if (index > -1) {
$scope.cards.splice(index, 1);
}
and I used ng-repeat to render each deck in the drag zone
<div class="row" ng-repeat="card in cards">
<img src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" alt="" vertical-scroll="false" ng-drag="true" ng-drag-data="card" ng-drag-success="onDragComplete($data,$event)" ng-center-anchor="true" width="100px">
</div>
and drop zones:
<div style="min-height: 300px;" class="col-xs-5" ng-drop="true" ng-scroll="false" ng-drag-move="true" ng-drop-success="onDropComplete($data,$event)">
<draggableClone></draggableClone>
<h2> Drop Area </h2>
<div ng-repeat="card in cardsDrop" ng-drag-success="onDragComplete($data,$event)" class="card">
<img src="http://www.download32.com/images/screen/vector_playing_cards-467278.png" class="card" alt="" width="100px">
</div>
</div>
In addition, I have added some styling to the ng-drag and ng-drop.

The ngDraggable library you're using does not support adding the element to a parent element (like document.body) once you start dragging. You need that, otherwise the element can never leave the sidebar and keep on being visible. That's how CSS works.
What you could do is use another library that supports adding the draggable element to another element, like jQuery UI:
app.directive('draggable', function() {
return function($scope, $element, $attrs) {
$element.draggable({
appendTo: 'body',
stop: function(event, ui) {
// Handle new position
}
});
};
});
There are probably AngularJS wrappers for Jquery UI out there that do this for you in a more declarative style, or other ngDraggable alternatives that support this.

Related

From bootstrap Grid columns to carousel

So this is what I’m hoping to accomplish.
I currently have a bootstrap grid displaying 1 row and 4 columns.
On desktop devices the 4 columns appears next to each other
On tablets they appear in a 2 x 2 grid and in Mobile devices they appear 4 rows with 1 column.
Is it possible to make it so that when in tablet or mobile to have a carousel that I can slide between the 4 columns? So that when in Tablet there are 2 slides with two of the columns in each slide and when in mobile 4 slides with 1 column in each slide?
Here is my current grid code.
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<div class="how container">
<div class="title">SUBSCRIBE IN JUST 4 EASY STEPS</div>
<div class="row no-gutters">
<div class="col text-center">
<img src="https://dummyimage.com/400x400/000/fff" style="height:200px;">
<span>SIGN UP</span>
</div>
<div class="col text-center">
<img src="https://dummyimage.com/400x400/000/fff" style="height:200px;">
<span>SELECT AGE GROUP</span>
</div>
<div class="w-100 d-block d-lg-none"></div>
<div class="col text-center">
<img src="https://dummyimage.com/400x400/000/fff" style="height:200px;">
<span>CHOOSE A SUBSCRIPTION PLAN</span>
</div>
<div class="col text-center">
<img src="https://dummyimage.com/400x400/000/fff" style="height:200px;">
<span>HAVE FUN</span>
</div>
</div>
<div class="row text-center pt-3">
<div class="col">
<button type="button" class="btn btn-dark btn-lg">GET STARTED</button>
</div>
</div>
</div>
If Bootstrap is the only library you're allowed to use, I would imagine you would have to have duplicate contents and show/hide one of them on different breakpoints for carousels or just regular 4-column content.
If that's not the case, I would highly recommend you to use OwlCarousel! That has everything you're looking for.
HTML
<div class="how container">
<h4 class="title">
SUBSCRIBE IN JUST 4 EASY STEPS
</h4>
<div class="owl-carousel owl-theme">
<div class="item">
<figure class="figure">
<img src="https://loremflickr.com/600/200?random=1"
class="figure-img img-fluid w-100" />
<figcaption class="figure-caption">
SIGN UP
</figcaption>
</figure>
</div>
<div class="item">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
</div>
As you can see, basically you just need a wrapper with a class .owl-theme that wraps a collection of .items. Inside each item, you can have any content you want. Here I just demonstrated to have a <figure /> inside of each item.
JavaScript
Make sure you've loaded jQuery first, then the javascript file of OwlCarousel, and then 2 style files: 1 core css and 1 theme. Installation details are documented here.
$(function() {
$('.owl-carousel').owlCarousel({
loop: false,
margin: 0,
nav: false,
responsive:{
0:{
items:1
},
768:{
items:2
},
992:{
items:4
}
}
});
});
See, in the responsive option, this is where you define how many items you want per break point. More info from their documentation site here!
Result
demo: https://jsfiddle.net/davidliang2008/mvn3k08u/22/

Expand / Show and hide div element in a listview

As you can see, is this a list view and my mission is when you click on an element / div then the div with the images expand / show. Now that is easy, even for a backend developer, but I would like to:
1. when I click again on the same element, then the element will hide.
2. When I click on another element, then the element that is already expand will hide and the other element that I click on, will expand / show.
I need Script and CSS for this please.
<div class="row">
#foreach(var post in CurrentPage.Children)
{
<div class="col-md-12">
<div class="content equal" onclick="showhide()">
<a href="#post.Url">
<div class="date">#post.CreateDate.ToLongDateString()</div>
<h2>#post.Name</h2>
<p>#Umbraco.Truncate(post.Introduction, 240, true)</p>
</a>
</div>
<div class="images(-expand)">
<img src="#post.Image" />
</div>
</div>
}
</div>
Try as follows.
$('.content.equal').click(function() {
$('.content.equal').not(this).next().slideUp();
$(this).next().slideToggle();
});
$('.content.equal a').click(function(event) {
event.preventDefault();
});
.images {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col-md-12">
<div class="content equal">
<a href="#post.Url">
<div class="date">12-01-2017</div>
<h2>Name1</h2>
<p>#Umbraco.Truncate(post.Introduction, 240, true)</p>
</a>
</div>
<div class="images">
<img src="http://i164.photobucket.com/albums/u8/hemi1hemi/COLOR/COL9-6.jpg" />
</div>
</div>
<div class="col-md-12">
<div class="content equal">
<a href="#post.Url">
<div class="date">12-01-2017</div>
<h2>Name1</h2>
<p>#Umbraco.Truncate(post.Introduction, 240, true)</p>
</a>
</div>
<div class="images">
<img src="http://i164.photobucket.com/albums/u8/hemi1hemi/COLOR/COL9-6.jpg" />
</div>
</div>
<div class="col-md-12">
<div class="content equal">
<a href="#post.Url">
<div class="date">12-01-2017</div>
<h2>Name1</h2>
<p>#Umbraco.Truncate(post.Introduction, 240, true)</p>
</a>
</div>
<div class="images">
<img src="http://i164.photobucket.com/albums/u8/hemi1hemi/COLOR/COL9-6.jpg" />
</div>
</div>

Setting height based on another elements height over multiple instances in jQuery

I'm using jQuery to obtain the height from one div and add that via css into another
So i have the following layout as an example:
<div class="row">
<div class="column image">
<img src="image.jpg" />
</div>
<div class="column content">
<p>Content</p>
</div>
</div>
<div class="row">
<div class="column content">
<p>Content</p>
</div>
<div class="column image">
<img src="image.jpg" />
</div>
</div>
with the following jQuery
function showHeight( element, height ) {
$( "div.image" ).css("height", height);
}
showHeight( "div", $( ".content" ).height() );
where i would take the height from ".content" & recur that height into ".image"
now obviously this works for say one instance but I'm looking to have this over multiple instances rather than write a function for each.
You can loop through the .image elements and change its height according to the prev('.content') element.
function updateHeight() {
// loop through all image elements
$( "div.image" ).each(function(){
// get `height` of the previous `.content` element
var contentHeight = $(this).prev('.content').height();
// set height
$(this).css("height", contentHeight);
});
}
//call one method to update
updateHeight();
This will only work when the .image comes after .content. I reordered the HTML like this:
<div class="row">
<div class="column content">
<p>Content</p>
</div>
<div class="column image">
<img src="image.jpg" />
</div>
</div>
<div class="row">
<div class="column content">
<p>Content</p>
</div>
<div class="column image">
<img src="image.jpg" />
</div>
</div>
UPDATE:
To find closest .content in any order, change this
var contentHeight = $(this).prev('.content').height();
to
var contentHeight = $(this).prev('.content').height() || $(this).next('.content').height();

Use Kendo UI Flip Effects / Combined Effects for multiple items on the same page

I need to use kendo ui to display between 6-60 items. Each using the flip effect here http://demos.telerik.com/kendo-ui/fx/combined
The products will be loaded from the database with the unique id like this:
<div class="row">
<div class="col-md-4 product-container">
<div id="productID1" class="productID">
<div class="product">
<div id="product-back1" class="product-desc">
<p>BACK</p>
</div>
<div id="product-front1" class="product-image">
<p>FRONT</p>
</div>
</div>
</div>
</div>
<div class="col-md-4 product-container">
<div id="productID2" class="productID">
<div class="product">
<div id="product-back2" class="product-desc">
<p>BACK</p>
</div>
<div id="product-front2" class="product-image">
<p>FRONT</p>
</div>
</div>
</div>
</div>
<div class="col-md-4 product-container">
<div id="productID3" class="productID">
<div class="product">
<div id="product-back3" class="product-desc">
<p>BACK</p>
</div>
<div id="product-front3" class="product-image">
<p>FRONT</p>
</div>
</div>
</div>
</div>
The problem is I need multiple panels on the page how can I make each "front" and "back" click unique.
var el = kendo.fx($('div[id^=productID]')),
flip = el.flip("horizontal", $('div[id^=product-front]'), $('div[id^=product-back]')),
zoom = el.zoomIn().startValue(1).endValue(1);
flip.add(zoom).duration(200);
$('div[id^=product-front]').click(function () {
flip.stop().play();
});
$('div[id^=product-back]').click(function () {
flip.stop().reverse();
});
I've tried loading each item into an array but have not found a good way to assure the correct item will be flipped.
Since every div[id^=product-front] is a child of div[id^=productID], you can find the children of that and use it.
replace flip.stop().play(); with
kendo.fx($(this)).flip("horizontal", $(this).children()[0], $(this).children()[1]).stop().play();

What is the best practice to enable the user to view certain categories on a portfolio page?

Here I have a portfolio page of 4 categories, when you first land on the page you will see all of them. BUT you have the option to chose form the menu which category to only show and hide all the rest.
<div class="wrapperA">
<div class="contentB">
<div id="portfolio-topSection">
All
Visual Identity
Photography
</div>
</div>
</div>
<div class="wrapperB">
<div class="content">
<div id="portfolio-gallerySection">
<div class="grid">
<div class="itemWrapper categoryAll">
<img alt="" src="assets/images/me.png">
<span><p>Click To View Project</p></span>
</div>
<div class="itemWrapper categoryWebDesign">
<img alt="" src="assets/images/11.png">
<span><p>Click To View Project</p></span>
</div>
</div>
<div class="grid">
<div class="itemWrapper categoryVisualIdentity">
<img alt="" src="assets/images/me.png">
<span><p>Click To View Project</p></span>
</div>
<div class="itemWrapper categoryPhotography">
<img alt="" src="assets/images/me.png">
<span><p>Click To View Project</p></span>
</div>
</div>
<div class="grid">
<div class="itemWrapper category-WebDesign">
<img alt="" src="assets/images/11.png">
<span><p>Click To View Project</p></span>
</div>
<div class="itemWrapper category-WebDesign">
<img alt="" src="assets/images/me.png">
<span><p>Click To View Project</p></span>
</div>
</div>
</div>
</div>
</div>
$('.categoryButton-All').click(function() {
$(this).addClass('portfolio-topSectionClicked');
$("#portfolio-gallerySection .grid div").not(".categoryAll").fadeOut();
});
In a fiddle: http://jsfiddle.net/4HFvx
I've updated your fiddle below. I supply each filter button with a "data-filter" attribute, then apply this as a class to your gallery using the following script:
;(function(){
var $portfoliogallerySection = $('#portfolio-gallerySection'),
$filterbuttons = $('#portfolio-topSection a');
$filterbuttons.on('click', function(){
var $this = $(this);
$filterbuttons.removeClass('active');
$this.addClass('active');
$portfoliogallerySection.attr('class', $this.data('filter'));
});
}());
Then use css to hide / show appropriately categorised items in the gallery, i'll leave the transitions to you.
http://jsfiddle.net/4HFvx/4/

Categories