how to implement Draggable element in ionic v1 - angularjs

Hi Guys My requirement is to make an element draggable across the screen and set the position of the element to the place where users stops dragging. So far I am able to make a element draggable across the screen but once released it is going back to its old position (position where it was earlier) I am using ngDraggable directive of angular. Sorry I am new to Ionic and angular. Any help will be highly appreciated.
My code goes as follows
<div ng-drag="true" id="draggableAxis" ng-style="{{draggedStyle}}" ng-drag-success="onDragComplete($data,$event)">
<img src="img/axis.png" >
<img ng-src="img/other.png" style="width:75px">
</div>
In my controller:
$scope.draggedStyle = {top: '96px',
right: '90px'};
var onDraggableEvent = function(evt, data) {
if(evt.name=='draggable:start'){
console.log('draggable-start');
console.log(data.x);
console.log(data.y);
}else{
console.log('draggable-end');
console.log(data);
console.log(data.element.centerX +' '+data.element.centerY);
console.log(evt);
$scope.setPosition(data);
}
}
$scope.onDragComplete=function(data,evt){
console.log("drag success, data:", data);
console.log(evt);
}// this fn doesnot gets triggered
$scope.$on('draggable:start', onDraggableEvent);
$scope.$on('draggable:end', onDraggableEvent);
$scope.setPosition=function(data){
$scope.draggedStyle = {
top: data.x+'px',
right: data.y+'px'
};
}
SCREEN SHOT OF MOBILE VIEW

I updated the fix to https://plnkr.co/edit/fVaIUVvAd7jLETkwVepm?p=preview
One of the problems was
ng-style="{{draggedStyle}}"
which should be
ng-style="draggedStyle"
Also, I switched the setPosition method to flip the x and y and used left because x indicates position from the left and not right.
$scope.setPosition = function(data) {
$scope.draggedStyle = {
top: data.y + 'px',
left: data.x + 'px'
};
}
Hope that helps

Related

Is this a good time to use React refs?

I'm looking to recreate this elastic nav in a React component (see Codepen). Right now it's written in jQuery--and I'm having trouble getting the position and width in React. Would using React refs be a good way to access that information?
Any thoughts or insight would be greatly appreciated. I've been trying to figure out how to recreate this all week.
The click handler was pretty simple in React. I just created a function and then used onClick. And setting the active class wasn't too hard either. I ended up using a prop.
But these two sections of the code are where I'm stuck--and unsure how to recreate in React:
var activeItem = tabs.find('.active');
var activeWidth = activeItem.innerWidth();
$(".selector").css({
"left": activeItem.position.left + "px",
"width": activeWidth + "px"
});
var activeWidth = $(this).innerWidth();
var itemPos = $(this).position();
$(".selector").css({
"left":itemPos.left + "px",
"width": activeWidth + "px"
});
Here's the full JavaScript/jQuery:
var tabs = $('.tabs');
var selector = $('.tabs').find('a').length;
var activeItem = tabs.find('.active');
var activeWidth = activeItem.innerWidth();
$(".selector").css({
"left": activeItem.position.left + "px",
"width": activeWidth + "px"
});
$(".tabs").on("click","a",function(e){
e.preventDefault();
$('.tabs a').removeClass("active");
$(this).addClass('active');
var activeWidth = $(this).innerWidth();
var itemPos = $(this).position();
$(".selector").css({
"left":itemPos.left + "px",
"width": activeWidth + "px"
});
});
And here's the full HTML:
<div class="wrapper">
<nav class="tabs">
<div class="selector"></div>
</i>Popular
Upcoming
</i>My Movies
</i>Search
</nav>
</div>
And here's the link to the project with CSS (if you want to see it in action).
I'd love for this to be compartmentalized in a single component if possible. But if it needs to have some sub-components that's okay as well.
Thank you!
You can absolutely make this work in react, and you are on the right track.
You can use this syntax to create references to an element in React:
<input ref={input => this.myInput = input} />
Which can then be accessed by a handler tied to your tab links. For example:
handleTabClick = (e, index) => {
e.preventDefault()
position = {left: this.myInput.offsetLeft, top: this.myInput.offsetTop} // Make sure this is the correct JS!
width = this.myInput.offsetWidth // Make sure this is the correct JS!
}
render () {
return (
...
<a href="#" class="tab" onClick={e => handleClick(e, 1)}>Tab 1</a>
...
)
}
I'm not 100% sure about the element properties being accurate (width, position), but you can do a quick google/search on stackoverflow to find the correct ways to do it in vanilla JS instead of jQuery. You can also use this site for native JS methods which accomplish the same as jQuery: http://youmightnotneedjquery.com/

Angular1 perfect scrollbar : After refreshing the data, how to get it back to the top

I set the scroll bar for the table. When I scroll to the bottom of the current page and click on the next page, the scroll position does not get back to the top. How can I get it back to the top after the data is refreshed? Thanks.
It could be done a lot of ways, how are you handling pagination? You could place a ng-click on the pagination button that scrolls you to the top. A code sample or plunkr would be helpful.
You could do something like below using regular JS.
var btn = document.getElementById('x');
btn.addEventListener("click", function() {
var i = 10;
var int = setInterval(function() {
window.scrollTo(0, i);
i += 10;
if (i == 200) clearInterval(int);
}, 20);
})
body {
background: lightblue;
height: 600px;
}
\HTML in view layer
<button id='x'>click</button>

Combining <ons-sliding-menu> and <ons-carousel>

I have an app with <ons-sliding-menu> and a page with <ons-toolbar> and a horizontal <ons-carousel> covering the remaining space.
For the <ons-sliding-menu> the parameter swipe-target-width="50px" is set.
Is there a way to tell the <ons-carousel> to ignore events originating from the most left 50px and let these go to the menu?
Currently there is no option to make the carousel ignore events on one side, but perhaps you can make a trick. You can put a div at the same level than the carousel and let it take the clicks instead of the carousel in the area you need:
<div class="cover"></div>
<ons-carousel>
...
</ons-carousel>
You can change these values to fit your case:
.cover {
position: absolute;
left: 0;
height: 100%;
width: 200px;
z-index: 1;
}
Check it out here: http://codepen.io/frankdiox/pen/YqKOJE
Hope it helps!
After some experimentation, I came to the solution to inject the necessary functionality directly in the drag event handlers of the OnsCarouselElement. For this purpose I have introduced the attribute swipe-ignore-left for the <ons-carousel>. The other sites could easily be added when needed.In order to inject the functionality, load this JS-Code after loading onsenui.js:
(function () {
'use strict';
/****************************************************************
Checks the current event against the attribute swipe-ignore-left.
****************************************************************/
window.OnsCarouselElement.prototype._ignoreDrag = function (event) {
var attr = this.getAttribute('swipe-ignore-left');
if (attr === undefined) return false;
var left = parseInt(attr, 10);
if (left === undefined || left < 1) return false;
var startX = event.gesture.center.clientX - event.gesture.deltaX;
return startX < left;
};
/****************************************************************
Save the original drag-event-handlers
****************************************************************/
var originalCarouselOnDrag = window.OnsCarouselElement.prototype._onDrag;
var originalCarouselOnDragEnd = window.OnsCarouselElement.prototype._onDragEnd;
/****************************************************************
Override: OnsCarouselElement.prototype._onDrag
****************************************************************/
window.OnsCarouselElement.prototype._onDrag = function (event) {
if (this._ignoreDrag(event)) return;
originalCarouselOnDrag.apply(this, arguments);
};
/****************************************************************
Override: OnsCarouselElement.prototype._onDragEnd
****************************************************************/
window.OnsCarouselElement.prototype._onDragEnd = function (event) {
if (this._ignoreDrag(event)) return;
originalCarouselOnDragEnd.apply(this, arguments);
};
})();
To preserve for example the left 20 pixel for the <ons-sliding-menu>, this HTML is to provide:
<ons-sliding-menu ... side="left" swipeable swipe-target-width="20px" />
...
<ons-carousel ... swipeable swipe-ignore-left="20px" />

When zooming, circle gets 'dragged' from original position

I'm using mapbox.js and map.css to create a map with a simple circle drawn on it, and nothing else. (working jsfiddle) On the example that I did without angular, the zoom works as it should (meaning, it stays on the same position when zooming).
When I integrated with the example and I zoom, the circle gets dragged slightly to the top left when zooming out and to the bottom right when I zoom in, in the end returning to the original position when the zoom stops.
On the angular project I'm using require to load the scripts to the page and the view that has the map is not the first one that is loaded. I am not using a directive for leaflet, just using the files. The code is exactly the same from the example to the angular project, the only difference is that I am not using a script tag in the html file as I was in the example (since the code has been moved to the controller).
I wanted the behaviour to be the same as it was in the example but at this stage I don't know what might be causing it besides the fact that is not the view that is first being loaded.
Here's the view code:
<div id="leafletMap" style="width: 500px; height: 300px;"></div>
Here's the code in my controller:
/* globals L, $ */
define(['angular'], function (angular) {
'use strict';
/**
* #ngdoc function
* #name rmsPortalApp.controller:ViewMapCtrl
* #description
* # ViewMapCtrl
* Controller of the rmsPortalApp
*/
angular.module('rmsPortalApp.controllers.ViewMapCtrl', [])
.controller('ViewMapCtrl', function ($scope, Data) {
var ownerCircleLayer;
L.Map = L.Map.extend({
openPopup: function (popup) {
// this.closePopup(); // just comment this
this._popup = popup;
return this.addLayer(popup).fire('popupopen', {
popup: this._popup
});
}
});
var map = L.map('leafletMap', {
touchZoom: true,
dragging: true
}).setView([39.678, -8.229], 6);
/* Initialize the SVG layer */
//map._initPathRoot();
/* SVG from the map object */
//var svg = d3.select("#map").select("svg");
var southWest = [85.05, -180.01];
var northEast = [-85.06, 180.05];
var bounds = L.latLngBounds(southWest, northEast);
map.setMaxBounds(bounds);
L.tileLayer('http://api.tiles.mapbox.com/v4/bmpgp.010fd6a5/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoiYm1wZ3AiLCJhIjoiOWY4NGYwN2VjZDg0MGI1ZjdmMWI3ZjdlNGNmY2NmNmQifQ.FZ5cr4mO3iDKVkx9zz4Nkg', {
attribution: '© Powered By CGI',
minZoom: 3,
maxZoom: 18,
id: 'bmpgp.010fd6a5',
accessToken: 'pk.eyJ1IjoiYm1wZ3AiLCJhIjoiOWY4NGYwN2VjZDg0MGI1ZjdmMWI3ZjdlNGNmY2NmNmQifQ.FZ5cr4mO3iDKVkx9zz4Nkg'
}).addTo(map);
setOwnerCircle()
function setOwnerCircle() {
ownerCircleLayer = new L.layerGroup();
var ownerCircle = L.circle([39, -8], 3000, {
color: 'red',
opacity: 1,
weigth: 1,
fillOpacity: 0.0,
className: 'leaflet-zoom-animated'
});
ownerCircleLayer.addLayer(ownerCircle);
var circleBounds = ownerCircle.getBounds();
// Image popup
var endLat = circleBounds.getCenter().lat - 0.10000;
var endLon = circleBounds.getEast();
map.addLayer(ownerCircleLayer);
addedOwnerCircle = true;
}
})
});
EDIT:
I have tried putting it in the first view that is being loaded, it still happens.
Found the reason why it was happening:
When double checking the actual mapbox.js and mapbox.css I noticed that my css was wrong, upon replacing it with the right mapbox.css it stopped doing the dragging. Thank you for the help regardless.

Responsive sticky sidebar, need to update width

I've got a responsive sticky sidebar started here: http://codepen.io/cmegown/pen/fjqzH. I've got the sticky part down, and it's responsive in relation to the width of the original viewport width. However, if you scroll down and then change the viewport size you'll see that the width of the sidebar does not change.
I know I need to update the sidebarWidth variable, but I'm sure exact how/where to do that.
Any help is appreciated, thanks!
EDIT:
This one kind of got left behind amid some other projects, but I'm back to finish this. I got a little further, but still can't seem to figure out how to update the sidebar width if the user scrolls down the page then expands their browser (or rotates their device). I have some commented code in the JS panel where I left off.
Just put the width calculation in your scroll function.
$(function () {
// cache selectors
var wrapper = $('.wrapper');
var sidebar = $('.sidebar');
// get some maths
var sidebarTop = sidebar.offset().top;
var sidebarOffset = 25; // is .wrapper padding
// sticky logic
$(window).on('scroll', function () {
var windowTop = $(window).scrollTop();
var sidebarWidth = Math.round(wrapper.width() * 0.3); // is .sidebar width
if (sidebarTop < (windowTop + sidebarOffset)) {
sidebar.css({
position: 'fixed',
top: sidebarOffset,
width: sidebarWidth
})
} else {
sidebar.css({
position: 'static',
width: '30%' // original CSS value
})
}
})
})
There's a little bit of overhead there, since it has to calculate the width every time you scroll. The alternative would be to put it into a $(window).resize() function so it figures out the width when you resize the window.

Resources