How to reload element attribute inside jQuery droppable() - javascript

I have an inventory and every time a user deletes an item (drags it to the trash bin) I check if this item is a stack and remove 1 if it is.
The problem is that the stack number stays the same each time the user drops it
$('#trash-wrapper').droppable({
accept: ".item",
drop: function(event, e){
// If the trashed item has a stack that is bigger than 1, do not remove the element but remove 1 from the stack and return the item back
if(e.draggable.find('.inventory-stack').data('stack-count') > 1){
var count = e.draggable.find('.inventory-stack').data('stack-count');
e.draggable.find('.inventory-stack').attr('data-stack-count', (count - 1)).html(count - 1);
_ajaxFetch("php/ajax/game/conq-delete-item.php", {dby : 'l', id: e.draggable.attr('data-loot-id')});
}
// Otherwise destory the element
else{
e.draggable.remove();
_ajaxFetch("php/ajax/game/conq-delete-item.php", {dby : 'i', id: e.draggable.attr('data-item-id')});
}
}
});
The problem is that Count stays always the same. If there is stack of 20, the first drop works, it changes the attribute and html to 19, but all other drops still use the count variable declared first - 20, so it never goes more than 1 below.
I even tried
e.draggable.find('.inventory-stack').attr('data-stack-count', (e.draggable.find('.inventory-stack').data('stack-count') - 1)).html(e.draggable.find('.inventory-stack').data('stack-count') - 1);
Doesnt work as well

Ughhhhhh
data('stack-count');
Seems to save this globally and will not be replaced on new call
attr('data-stack-count');
Fixed it :/

Related

Slick Carousel - The "slickRemove" method is unable to remove the "slick-cloned" slide/item based on the "click" event or "data-slick-index" attribute

short description of the bug / issue, provide more detail below.
I am building a drag-and-drop quiz app. If a user drags a cloned item ( slick generates cloned items in infinite loop option by default) and drops it at the correct dropzone, I want to remove the dropped item from the carousel based on "data-slick-index" attribute value of the dropped item.
But the "slickRemove" method of Slick Carousel is unable to remove the "slick-cloned" slide + its original slide based on the "click" event on the cloned item or "data-slick-index" attribute value of the cloned item.
====================================================================
[ paste your jsfiddle link here ]
http://jsfiddle.net/anisur5/ehpacfvj/30/
====================================================================
Steps to reproduce the problem
Go to this link: http://jsfiddle.net/anisur5/ehpacfvj/30/
Click on the second dot (•) and Inspect "slide10" which contains
data-slick-index="-1". If you click on it (slide10), Slick js is
unable to delete the clicked item.
It happens whenever I click on
the "slick-cloned" slides.
====================================================================
What is the expected behaviour?
I want slick to remove the clicked item even though it is a "slick-cloned" item.
====================================================================
What is observed behaviour?
Slick's "slickRemove" method can not delete the clicked item if the item is "slick-cloned".
====================================================================
More Details
Which browsers/versions does it happen on? => All
Which jQuery/Slick version are you using? => Latest
Did this work before? => No
Here is the code that slick.js uses to remove slides. I added a comment tag for return false; so that Slick can remove items that come with negetive value in "data-slick-index" attribute( I also tried to remove items based on "data-slick-index" ).
Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) {
var _ = this;
if (typeof(index) === 'boolean') {
removeBefore = index;
index = removeBefore === true ? 0 : _.slideCount - 1;
} else {
index = removeBefore === true ? --index : index;
}
if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) {
// return false;
}
_.unload();
if (removeAll === true) {
_.$slideTrack.children().remove();
} else {
_.$slideTrack.children(this.options.slide).eq(index).remove();
}
_.$slides = _.$slideTrack.children(this.options.slide);
_.$slideTrack.children(this.options.slide).detach();
_.$slideTrack.append(_.$slides);
_.$slidesCache = _.$slides;
_.reinit();
};
If you add the count of original slides to the negative data-slick-index of the clones, it should give you the index of the original. Only slick does not appear to update that value correctly - so by using that alone, I ended up removing slides with a higher index than the clicked one, when clicking on an original.
Only workaround I could find on the quick, is to store the reference to the slide, on the slide, before the slider gets initialized - then the clones will still refer to the original. Via that reference, you can then find the index of the original in the list of original slides (exclude the clones), and then use that value to remove the slide.
// before slider initialization:
$('.slider div').each(function(i,e) {
$(e).data('self', e);
});
// slider init here
// ...
//Remove slick item based on click.
$(".slider").on("click", ".slick-slide", function() {
var originalSlide = $(this).data('self')
index = $('.slider .slick-slide:not(.slick-cloned)').index(originalSlide);
$(".slider").slick('slickRemove', index);
});
http://jsfiddle.net/1hx5s39z/2/

Current slide number of total in Vue Slick Carousel

I am trying to make current number and total number of slides using vue-slick-carousel.
This is what I tried so far.
<VueSlickCarousel ref="carousel">
<div>1 <button tabindex="-1">11</button></div>
<div>2 <button tabindex="-1">22</button></div>
<div>3 <button tabindex="-1">33</button></div>
<div>4<button tabindex="-1">44</button></div>
</VueSlickCarousel>
methods: {
customPaging: function (slider, i) {
var slideNumber = i + 1,
totalSlides = slider.slideCount;
return (
'<a class="custom-dot" role="button" title="' + slideNumber + ' of ' + totalSlides + '"><span class="string">' + slideNumber + '</span></a>'
);
},
},
But this is not working.
And this is vue-slick-carousel API url below.
https://github.com/gs-shop/vue-slick-carousel/blob/master/docs/API.md#methods
What do i need to fixed the code to show a current slide number and total slide.
ex) "3/10"
I had the same problem recently.
This probably comes late, but to whom it may still concern:
If you want to display current page numbers instead of the default dots, there is an example at the bottom of this VueSlickCarousel documentation page and you should be good.
If you want to display the current page number only once anywhere on your page, I found a solution that worked for me:
this.$refs solution did not work for me, but this was likely due to v-if that I was using to render the <VueSlickCarousel>.
v-if and this.$refs don't like each other very much - see also Vue.js refs are undefined, even though this.$refs shows they're there.
Eventually I tried looking at the events that the children emitted in Vue Devtools and I found this afterChange event.
The afterChange event is fired each time you move your carousel to the next page (regardless of whether you drag-slide or click the arrow) and contains a very useful param - the current page index. In my case, this param starts at 0 and for each change it is incremented or decremented by 3 - that is because my carrousel settings are set to slidesToScroll : 3.
So my solution was to:
Add event listener like this:
<VueSlickCarousel #afterChange="afterPageChange">
Create the sliderPageIndex in your data with the initial value 0.
data() {
return {
sliderPageIndex: 0;
}
}
Create the afterPageChange in methods: {}.
methods: {
afterPageChange(page) {
this.sliderPageIndex = page;
}
}
Create the currentPage in computed: {} with some additional logic to compensate for the abovementioned slidesToScroll setting and for the sliderPageIndex starting at 0, like this:
computed: {
currentPage() {
// always display 1 if page index is 0
if (this.sliderPageIndex == 0) {
return 1;
} else {
// compensate for slidesToScroll settings and compensate the shift by 1
return this.sliderPageIndex / this.carouselSettings.slidesToScroll + 1;
}
},
}
Now you should have access to the currentPage computed property and can use it anywhere in your <template>.
When it comes to the totalPages, I compute it from the length of the picture array that I send to the carousel instead of taking it from the carousel directly. Here, I also compensate for carouselSettings - if this requires further explanation, let me know.
You can read more about the VueSlickCarousel events here.
Hope this will be of use to someone! :)
Cheers and have a nice day.

Coding custom Screen Navigation into Lightswitch HTML

I would like to have Button action event in LS HTML go slightly against the built-in navigation framework.
Specifically, to have LS navigate from one AddEditScreen to another AddEditScreen automatically, triggered by this Button event.
The trick is this - I need it to navigate to the AddEditScreen of the "next item up" in the Browse Screen List, without returning to the Browse Screen.
Example:
Select item 'ABC01' on a Browse Screen > Navigate to the AddEditScreen for 'ABC01' > edit 'ABC01' > when finished editing, trigger an event that will enable LS to navigate directly to the AddEditScreen for 'ABC02' from the Browse Screen list.
I have an open mind about what that event could be. A Button...anything at all.
I have created a Button and chose 'Write my own method'.
Does this look even close to code that will work, or will LS need to get the value of 'ABC01' from a query of some type?
myapp.AddEditHoldingInventory.Method_execute = function (screen) {
// Write code here.
var navigateToNextScreen = function (Method) {
return screen.getStrRqsNum().then(function (StrRqsNum) {
if (!!StrRqsNum) {
return myapp.applyChanges().then(function () {
var paramValue = (Number(StrRqsNum) += 1).toString();
return myapp.ShowAddEditHoldingInventory(id);
}
});
});
}
The code above is modified by me, and I am not a programmer or developer. It is snippets from pieces I have gathered and am trying to make sense of.
What the code is trying 'miserably' to achieve, is:
get the value of StrRqsNumber > save the edits made on the screen > add +1 to the value of StrRqsNumber > navigate to the AddEditSCreen of the record with the new value.
StrRqsNumber = a column with a value. It is unique and identifies an asset. This is most likely NOT the best way to achieve what I am trying to achieve, so I am here for advice. I don't have to use this as the parameter, as long as I can hit the 'next item up' from the list.
Thank you very much for any input. I will be SO stoked to get this behavior working.
This problem was solved by joshbooker. Here was the solution, which only needed minimal project specific tailoring...
"Question
Vote as helpful
0
Vote
What I want to achieve is this, for example:
Browse Screen > Select item 1 of 15 in the list > scan in the information we need on the AddEditScreen for item 1 > hit the 'trigger', and have LS automatically Save that edit, then navigate to the AddEditScreen of item 2 of 15 > and so on.
Here is a working solution for this:
/// <reference path="~/GeneratedArtifacts/viewModel.js" />
myapp.BrowseHoldingInventories.selectNextStrRqsNum_execute = function (screen)
{///custom screen method to set selected item to next StrRqsNum
//calc next num
var nextNum = (Number(screen.HoldingInventories.selectedItem.StrRqsNum) + 1).toString();
// iterate collection data to find the next item
var nextItem = msls.iterate(screen.HoldingInventories.data)
.where(function (i)
{
return i.StrRqsNum == nextNum;
}).first();
if (nextItem)
{ //if found - select the item & return true
screen.HoldingInventories.selectedItem = nextItem;
return true;
}
else
{ //not found - return false
return false;
};
};
myapp.BrowseHoldingInventories.TapMethod_execute = function (screen) {
// tap method of list item on browse screen.
//handy way to save/set scroll position
var scrollTopPosition = $(window).scrollTop();
//currently selected item
var item = screen.HoldingInventories.selectedItem;
//showAddEditScreen - pass item
// beforeShown: setup binding on FieldB
//afterClosed: if commit & select next then recurse
myapp.showAddEditHoldingInventory(item, {
beforeShown: function (addEditScreen)
{//this executes before the screen is shown
//find the trigger field
var contentItem = addEditScreen.findContentItem("FieldB");
if (contentItem)
{ //databind to catch value change
contentItem.dataBind(contentItem.bindingPath, function(newValue){
if (newValue && contentItem.oldValue && newValue != contentItem.oldValue)
{ //if change then commit - this triggers close of addEditScreen
myapp.commitChanges();
}
contentItem.oldValue = newValue;
});
}
},
afterClosed: function (addEditScreen, navigationAction)
{//this executes after the screen is closed
//scroll browse screen to where we left off
$(window).scrollTop(scrollTopPosition);
//if commit
if (navigationAction == msls.NavigateBackAction.commit)
{ //try to select next item in list
if (myapp.BrowseHoldingInventories.selectNextStrRqsNum_execute(screen) == true)
{ //next item selected then recurse
myapp.BrowseHoldingInventories.TapMethod_execute(screen);
}
}
}
});
};
"

jQuery change ID of all DIVs with ID < than $(this).attr("id");

I have an sortable grid of elements, that updates its value to DB after user moves the element. The problem is, I don't know how to update the id of all previous elements to a new one without reloading the page.
In PHP, I would do something like this (code from FAQ of one of my older pages), but I can't use PHP (it has to happen without any page reloading, right after user places element he moved):
if ($old_order > $order){
$result = dbquery("UPDATE faq SET orders=orders+1 WHERE orders>='$order' AND orders<='$old_order'");
}else{
$result = dbquery("UPDATE faq SET orders=orders-1 WHERE orders>='$old_order' AND orders<='$order'");
}
I would like to do that with jQuery, basically I have 7 elements with id from 0 to 6 and every time user changes the position, I serialize it and send it with ajax to an php code that saves it.
What it does now:
Move elemtent 1 to position 4.
Saves and works.
Move element 3 to position 2
Moves element 1 from position 4 back to his old one, as the ID of it
is still 1 and not 4.
What I want to do:
Move element 1 to position 4
Change ID of element 1 from 1 to 4
Change ID of element 2, 3 and 4 by -1 to id 1, 2 and 3
I hope somebody understands me and can help me.
jQuery code I actauly use:
$(".content-page").sortable({
start: function(e,ui){
ui.placeholder.height($(".sorted-icons").outerHeight(true));
ui.placeholder.width($(".sorted-icons").outerWidth(true));
},
placeholder: 'placeholder',
items: '.sorted-icons:not(.new_icon)',
update: function(e,ui) {
var order = $(this).sortable("serialize") + '&order=icons' + '&content_id=' + $(this).attr("data-shortcut-id");
console.log(order);
$.post("page_ajax.php", order).done(function(data){
console.log(data);
}).fail(function(data){
console.log(data);
});
}
}).disableSelection();
Html code basically looks like this with content inside of that div thats irelevant:
echo "<div class='sorted-icons' id='icon_$id'>";
If you have any questions, just comment and Ill try to answer them and update the queston.
Fixed jQuery:
var i = 0;
$(this).children('.sorted-icons').each(function(){
$(this).attr('id', 'icon_' + i);
i++;
});
Still have problem with PHP part tho. Its saving them in weird orders.
Ok, so I had one little bug in my PHP code, but I managed to fix the jQuery with really simple pice of code:
$(".content-page").sortable({
start: function(e,ui){
ui.placeholder.height($(".sorted-icons").outerHeight(true));
ui.placeholder.width($(".sorted-icons").outerWidth(true));
},
placeholder: 'placeholder',
items: '.sorted-icons:not(.new_icon)',
update: function(e,ui) {
var order = $(this).sortable("serialize") + '&order=icons' + '&content_id=' + $(this).attr("data-shortcut-id");
console.log(order);
$.post("page_ajax.php", order);
// THIS PART //
var i = 0;
$(this).children('.sorted-icons').each(function(){
$(this).attr('id', 'icon_' + i);
i++;
});
// THIS PART //
}
}).disableSelection();
Hopefully might help somebody else.

adding class to array elements through loop

I need the loop that checks input fields from 'inputs' array, and if there are empty fields, special dialog need to be displayed near them, and after the dialog is displayed I need class 'style' to be added to the input field near which the dialog was displayed, then dialog should go to the next emppty field and add class 'style' to it. And so on until all empty inputs have class 'style'.
The problem is, in my loop after the dialog is displayed class 'style' is added only to the last element from the array, but it should be added to every empty element with delays in between.
This is my loop, but as I said it is not working properly:
for(i=0;i<inputs.length;i++){
var now = inputs[i];
var top = inputs[i].attr('top');
if(!now.val()){
if(dialog.css('display')=='none'){now.addClass('style');dialog.css('top',top).fadeIn(200);}
else{dialog.delay(300).animate({"top": top}, 500, function(){now.addClass('style');});
}else{now.removeClass('style');}}
P.S. Sorry for my English.
This is happening because the function that is calling 'addClass' is happening after the 300 millisecond animation. By that time, the value of the 'i' variable has changed because the for loop will continue to run.
You may just be able to have the 'now.addClass' call before the 'animate' and delay. Otherwise, you will have to break the loop and continue after the animation is complete to prevent the variable from being overwritten.
Here is an example of what I was talking about. The code below will process 1 input at a time and not continue to the next until the current one is finished processing (this code has not been tested):
var offset = -1;
var inputs = (something goes here)
iterateInputs();
function iterateInputs()
{
offset++;
if (typeof inputs[offset] != 'undefined')
{
eachInput();
}
else
{
// all done!
}
}
function eachInput()
{
var now = inputs[offset];
var top = inputs[offset].attr('top');
if (!now.val())
{
if (dialog.css('display')=='none')
{
now.addClass('style');
dialog.css('top', top).fadeIn(200, function(){
iterateInputs();
});
}
else
{
dialog.delay(300).animate({"top": top}, 500, function(){
now.addClass('style');
iterateInputs();
});
}
}
else
{
now.removeClass('style');
iterateInputs();
}
}

Categories

Resources