I'm using Gridstack for draggable div's.
How do I get the new value of data-gs-y (so to which y-axis the div was dropped).
Actually I tried this:
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="grid-stack" data-gs-width="12" data-gs-animate="yes">
<div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="12" data-gs-height="1" data-gs-id="facebook">
<div class="grid-stack-item-content">facebook</div>
</div>
<div class="grid-stack-item" data-gs-x="0" data-gs-y="1" data-gs-width="12" data-gs-height="1" data-gs-id="workbook">
<div class="grid-stack-item-content">workbook</div>
</div>
<div class="grid-stack-item" data-gs-x="0" data-gs-y="2" data-gs-width="12" data-gs-height="1" data-gs-id="pictures">
<div class="grid-stack-item-content">pictures</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(function () {
$('.grid-stack').gridstack({
disableResize: true,
removable: true
});
});
$('.grid-stack').on('dragstop', function(event, ui) {
var element = event.target;
var id = $(element).attr('data-gs-id');
var y = $(element).attr('data-gs-y');
alert(id + y);
});
$('.grid-stack').on('dropped', function (event, previousWidget, newWidget) {
alert('dropped'); // It's not thrown
});
$('.grid-stack').on('change', function(event, items) {
var element = items[0].el[0];
var id = $(element).attr('data-gs-id');
var y = $(element).attr('data-gs-y');
alert(id + y);
});
</script>
So the event dragstop and also change is given me the current/old value of the y-axis and the dropped event is not thrown..
How do I get the new value of the y-axis?
I think you can use "mutation observer" to listen changes to the attribute 'data-gs-y' on each div element. I wrote following code and verified on this demo http://gridstackjs.com/demo/knockout.html
var divs = document.querySelectorAll(".grid-stack-item");
var dragging = false;
divs.forEach(function(div){
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if(!dragging){
alert("new y-value " + div.getAttribute("data-gs-y"));
}
});
});
observer.observe(div, { attributes: true, attributeFilter: ['data-gs-y'] });
div.onmousedown = function(){ dragging = true;}
div.onmouseup = function(){ dragging = false;}
});
Related
I'm using the jquery and jquery UI plugin to drag and drop elements (folders and files) just like in a filebrowser.
I can manage to have the file go 'into' the folder, but not a folder to go into another.
Here is a demo :
There seems to be something conflicting, but I don't know where to look anymore.
The javascript is like this :
$(function () {
// fancytree is part of another script
$("#tree").fancytree({
expandLazy: true,
activate: function (event, data) {
var node = data.node;
if (node.data.href) {
window.open(node.data.href, node.data.target);
}
}
});
/* DRAG AND DROP STARTS HERE */
$(".listitems").draggable();
$(".droppable").droppable({
//preventCollision: true,
drop: function (event, ui) {
var draggableId = ui.draggable.attr("id");
var droppableId = $(this).attr("id");
//alert('FILE'+draggableId+' DROPED INTO '+droppableId);
$(this).append(ui.draggable);
var itemid = ui.draggable.attr('data-itemid');
var folderid = ui.draggable.attr('data-fldmid');
if (typeof folderid == 'undefined') {
folderid = 0;
}
if (typeof itemid == 'undefined') {
itemid = 0;
}
if (typeof droppableId == 'undefined') {
droppableId = 0;
}
$.ajax({
method: "POST",
url: "_ajax/filemanager/dragdrop.php",
//data : 'FileID='+ itemid +'&FolderID='+ droppableId,
data: 'FileID=' + itemid + '&FolderID=' + folderid + '&DropID=' + droppableId,
}).done(function (data) {
var result = $.parseJSON(data);
if (folderid == 0) {
//alert('FILE MOVED - FileID='+ itemid +'&FolderID='+ folderid+'&DropID='+ droppableId);
// Done moving file, hiding it
$("div#" + itemid).hide(500);
} else {
//alert('FOLDER MOVED - FileID='+ itemid +'&FolderID='+ folderid+'&DropID='+ droppableId);
// Done moving directory, hiding it
$("div#" + folderid).hide(500);
}
//$("div#"+folderid).hide(500);
//$("div#"+droppableId).hide(500);
});
}
});
$(".listitems").sortable();
$(".listitems").disableSelection();
var shouldCancel = false;
$('.dragMe').draggable({
containment: '.moveInHere',
revert: function () {
if (shouldCancel) {
shouldCancel = false;
return true;
} else {
return false;
}
}
});
$('.butNotHere').droppable({
over: function () {
shouldCancel = true;
},
out: function () {
shouldCancel = false;
}
});
});
And here is the html
<div class="box-body">
<div class="table-responsive mailbox-messages moveInHere" style="overflow: hidden; min-height:600px;">
<p>
<!--id, data-fldmid and data-itemid were added for testing purposes -->
<div class="boxFile small droppable listitems dragMe drag" id="D.4" data-fldmid='D.4' data-itemid='4'>
<a href="?n=9">
<div class="ffolder small yellow"></div>
</a>
<div class="boxFileTitle">Folder 1 (4)</div>
</div>
<div class="boxFile small droppable listitems dragMe drag" id="D.7" data-fldmid='D.7' data-itemid='7'>
<a href="?n=7">
<div class="ffolder small yellow"></div>
</a>
<div class="boxFileTitle">Folder A (7)</div>
</div>
<p>
<div style="" class="boxFile small listitems butNotHere dragMe drag" id="26" data-itemid='26'>
<img src='image.php?id=26' class='UploadedImageThumb'>
<div class="boxFileTitle">2016-12-12 14.50.14.jpg26</div>
<div class="boxFileOption">Preview | Edit | Trash</div>
</div>
</p>
<p>
<div style="" class="boxFile small listitems butNotHere dragMe drag" id="25" data-itemid='25'>
<img src='image.php?id=25' class='UploadedImageThumb'>
<div class="boxFileTitle">test.jpg25</div>
<div class="boxFileOption">Preview | Edit | Trash</div>
</div>
</p>
</p>
</div>
</div>
The 'butNotHere' class is to prevent files to be on top of each other. All this works fine, except the folder-into-folder dragging as described above.
I found the error, the variable in JS (folderid) had a letter 'D' in front of the real id. I did this during test to check if it was a file being moved or folder. So 'F' or 'D'.
So I changed this line
data-fldmid='D.7'
To this and it worked
data-fldmid='7'
I have been attempting to perform an ng-repeat inside an ng-repeat collapse. My inner ng-repeat, repeats the entire array inside of every div. I have tried to track by index but still no resolve:
<div class="col-md-4">
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">{{m.marketname}}
</div>
<div uib-collapse="!m.isCollapsed">
<div ng-repeat="s in stuff" >
<p>{{s.$$state.value.Address}}</p>
<p>{{s.$$state.value.GoogleLink}}</p>
<p>{{s.$$state.value.Products}}</p>
<p>{{s.$$state.value.Schedule}}</p>
</div>
</div>
</div>
</div>
Inside Controller:
_getLocation: function(key) { //extract latlng from _recordsCache
var latLong = this._recordsCache[key];
// console.log(latLong);
fmCoordinates.lat = latLong.lat;
fmCoordinates.lng = latLong.lng;
var promise = requestMarkets(fmCoordinates.lat,fmCoordinates.lng);
promise.then(function(marketData) {
$scope.marketResults = marketData.results; //receiving market data
$scope.quantity = 5; //limit market data to 5
$scope.marketInfo = [];
$scope.getInfo = function(){
return $scope.marketInfo;
}
for(var property in $scope.marketResults) {
var id = $scope.marketResults[property].id;
console.log(id);
$scope.marketInfo.push(getDetails(id));// brings back the details
};
console.log($scope.getInfo());
}, function(reason) {
console.log('Failed: ' + reason);
});
if( this._recordsCache.hasOwnProperty(key) )
return latLong;//then after use .loc attribute
else
return false;
},
You need to add the second array as a property of each item in first array. See below code:
HTML:
Instead of writing ng-repeat = "s in stuff", we will write ng-repeat = "s in m.stuff"
<div class="col-md-4">
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">{{m.marketname}}
</div>
<div uib-collapse="!m.isCollapsed">
<div ng-repeat="s in m.stuff" >
<p>{{s.$$state.value.Address}}</p>
<p>{{s.$$state.value.GoogleLink}}</p>
<p>{{s.$$state.value.Products}}</p>
<p>{{s.$$state.value.Schedule}}</p>
</div>
</div>
</div>
</div>
Controller:
First load marketResults array. Then in for loop, loop through each element in marketResults and load the second array using id and save it as stuff property for each element, so we can access second array using m.stuff in ng-repeat
_getLocation: function(key) { //extract latlng from _recordsCache
var latLong = this._recordsCache[key];
// console.log(latLong);
fmCoordinates.lat = latLong.lat;
fmCoordinates.lng = latLong.lng;
var promise = requestMarkets(fmCoordinates.lat,fmCoordinates.lng);
promise.then(function(marketData) {
$scope.marketResults = marketData.results; //receiving market data
$scope.quantity = 5; //limit market data to 5
for(var market in $scope.marketResults) {
market.stuff = getDetails(market.id);// brings back the details
};
}, function(reason) {
console.log('Failed: ' + reason);
});
if( this._recordsCache.hasOwnProperty(key) )
return latLong;//then after use .loc attribute
else
return false;
},
You can use ng-init to keep children on each parent row. Pass id to a getChild(m.id) and get child and then use it on second loop.
ng-init="rowchild = getChild(m.id)"
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5" ng-init="rowchild = getChild(m.id)">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">
{{m.marketname}}
</div>
<div uib-collapse="m.isCollapsed">
<div ng-repeat="s in rowchild">
<p>{{s.Address}}</p>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">{{m.marketname}}
</div>
<div uib-collapse="!m.isCollapsed">
<div>
<p>{{m.stuff.$$state.value.Address}}</p>
<p>{{m.stuff.$$state.value.GoogleLink}}</p>
<p>{{m.stuff.$$state.value.Products}}</p>
<p>{{m.stuff.$$state.value.Schedule}}</p>
</div>
</div>
</div>
</div>
</div>
//Inside Controller
_getLocation: function(key) { //extract latlng from _recordsCache
var latLong = this._recordsCache[key];
// console.log(latLong);
fmCoordinates.lat = latLong.lat;
fmCoordinates.lng = latLong.lng;
var promise = requestMarkets(fmCoordinates.lat,fmCoordinates.lng);
promise.then(function(marketData) {
$scope.marketResults = marketData.results; //receiving market data
$scope.quantity = 5; //limit market data to 5
$scope.marketInfo = [];
console.log($scope.marketResults);
for (var i = 0; i < marketData.results.length; i++){
marketData.results[i].stuff = getDetails(marketData.results[i].id);
};
}, function(reason) {
console.log('Failed: ' + reason);
});
if( this._recordsCache.hasOwnProperty(key) )
return latLong;//then after use .loc attribute
else
return false;
},
I have divs acting like a table and I want to loop through each div row in jquery and collect the column values (and also the row id)
How can I do it? code is in this jsffiddle
https://jsfiddle.net/DTcHh/24064/
HTML
<div id="tasksTableDiv">
<div class="row taskRow" id="1">
<div id="description_1"
class="col-sm-2 taskDescriptionCol">Description 1
</div>
<div id="colour_1"
class="col-sm-2 taskColourCol">Blue
</div>
</div>
<div class="row taskRow" id="2">
<div id="description_2"
class="col-sm-2 taskDescriptionCol">Description 2
</div>
<div id="colour_1"
class="col-sm-2 taskColourCol">Red
</div>
</div>
</div>
<button id="loopButton" type="button"
class="btn btn-sm btn-primary">Loop</button>
JS
$('#loopButton').on('click',function() {
var ids = [];
var row = $('.taskRow');
$.each( row, function() {
// get the id of each row and get the description and colour
// ids.push( push the id you got);
console.log("in loop" + row.html());
});
});
You can use jQuery's .map() to loop over the elements and create an array of extracted properties (demo):
$('#loopButton').on('click', function() {
var ids = [];
var rowsData = $('.taskRow').map(function(index, element) {
var $fields = $(this).find('div');
return {
id: this.id,
label: $fields.eq(0).text().trim(),
description: $fields.eq(1).text().trim()
};
}).toArray();
console.log(rowsData);
});
If you want to do it with plain javascript
var loopButton = document.getElementById("loopButton");
loopButton.addEventListener("click", function() {
let ids = [];
var rows = document.getElementsByClassName("taskRow");
Array.prototype.forEach.call(rows, function(r){
ids.push(r.id)
console.log(r.children[0].innerHTML)
})
console.log(ids);
});
i have to bind jqGrids inside an accordion (JQ UI) and here is my code :
here i draw the grid inside the accordion .
<div id="accordion" class="accordion-style2">
<div class="group">
#foreach (var mytable in lstmytable )
{
<h3 class="accordion-header">mytable.DAY_NAME</h3>
<div divgrid="true" id="myDiv_#mytable.DAY_ID">
<p>
<table grid="true" id="grid_table_#mytable.DAY_ID"></table>
<div pagerid="true" id="grid-pager_#mytable.DAY_ID"></div>
</p>
</div>
}
</div>
</div>
//here i get the ids from the grid and the pager
$("[divgrid='true']").each(function () {
var GridID = jQuery(this).find("table").attr("id");
var PagerID = jQuery(this).find("div").attr("id");
BindGrid(GridID, PagerID);
});
//here i bind the grids using different id each time .
BindGrid(gridID,PagerID)
{
var grid_selector = GridID;
var pager_selector = PagerID;
//my grid implementation
}
but it never bind any grid
i find out that the grid_selector need to be have a # before it to become like this
var grid_selector = "#" + GridID;
var pager_selector = "#" + PagerID;
I'm creating a form which allows the users to add additional content on the fly. The structure of the form is such that there are three dimensions to the form data, i.e., like a movie can play at different theatres and each theatre can have different showing times. The form, therefore has grandparent, parent and child divs, and the parent & child divs can be added to on the press of a button.
Here's a slimed-down version of the code for clarity
<div id="grandparent">
<div id="parent">
Parent 1
<div id="child">
Child 1
</div>
</div>
<button id="addChild">Add Child</button>
</div>
<button id="addParent">Add Parent</button>
<script>
$(function() {
var grandparent_div = $('#grandparent');
var parent_div = $('#parent');
var child_div = $('#child');
var p = $('#grandparent div#parent').size() + 1;
var c = $('#parent div#child').size() + 1;
$('#addChild').on('click', function() {
$('<div id="child">Child '+c+'</div>').appendTo(parent_div);
});
$('#addParent').on('click', function() {
$('<div id="parent">Parent '+p+'<div id="child">Child 1</div><button id="addChild">Add Child</button></div>').appendTo(grandparent_div);
});
});
</script>
JSFiddle here: http://jsfiddle.net/u2vUT/
I can create parent nodes fine, and I can even create child nodes of parents on the first level - the problem comes when trying to add children of dynamically-added parents. It's probably because the 'addChild' button is no longer unique, so $('#addChild').on('click') can't reference it. So, is there a way to make this work (preferably elegant!)?
You should not use ids, use class
<div id="grandparent">
<div class="parent">Parent 1
<div class="child">Child 1</div>
</div>
<button class="addChild">Add Child</button>
</div>
<button id="addParent">Add Parent</button>
then
$(function () {
var grandparent_div = $('#grandparent');
var parent_div = $('.parent');
var child_div = $('.child');
var p = grandparent_div.find('.parent').size() + 1;
grandparent_div.on('click', '.addChild', function () {
$('<div id="child">Child ' + ($(this).siblings().length + 1) + '</div>').insertBefore(this);
});
$('#addParent').on('click', function () {
$('<div class="parent">Parent ' + p + '<div class="child">Child 1</div><button class="addChild">Add Child</button></div>').appendTo(grandparent_div);
});
});
Demo: Fiddle