Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: Allow placeholder when target array is empty #480

Open
GregPeden opened this issue Oct 16, 2018 · 27 comments
Open

Suggestion: Allow placeholder when target array is empty #480

GregPeden opened this issue Oct 16, 2018 · 27 comments

Comments

@GregPeden
Copy link

Just an idea... it would be swell to be able to allow placeholder, perhaps provided as a named slot, which is displayed only when the target array is empty. As soon as an item is dragged in to the 'draggable' field, even before released, the placeholder is no longer rendered. This would appear like the first element being added is going to replace the placeholder upon release.

So one can imagine a note like "drop here to add things" with an infographic icon being in place of nothingness. This secondarily resolves the issue of maintaining a minimum height of the HTML element to allow use when empty.

This past issue discusses a similar need:
#335

@David-Desmaisons
Copy link
Member

In terms of API, using a named slot would totally makes senses. I like this proposal.
I will have to take a carefull look to check if this is doable.

@ThePendulum
Copy link

It would be convenient to be able to add this placeholder anywhere, not just inside of the target list, and make its disappearance optional, so it also addresses #457 more adequately.

@satvikpendem
Copy link

I would also second this, especially for nested components.

@madebycaliper
Copy link

Any news on this? @David-Desmaisons has this made it into your roadmap for a future version?

@David-Desmaisons
Copy link
Member

@madebycaliper still have no good idea on how to implement such a feature. I should not be abble to deliver it in the short/mid term.

@madebycaliper
Copy link

@David-Desmaisons thanks for the reply. it seems like a complex feature!

@Doogiemuc
Copy link

Doogiemuc commented Mar 26, 2019

Think out of the box. You have VUE at hand :-)

    <draggable v-model="list" .....>
       <div v-for="elem in list" :key="elem.order">These are your normal sorted elems</div>
       <p v-if="list.length==0" key="4711">This is shown when container is empty</p>
     </draggable>

(Ok you need a dummy key 4711.)

@David-Desmaisons
Copy link
Member

David-Desmaisons commented Mar 26, 2019

@dominiczaq Well your sample is exactly an example that IS NOT WORKING, because vue.draggable needs the inner children to map the list

@madebycaliper
Copy link

@Doogiemuc yea, I've implemented a working solution a number of times, as I use this component in a bunch of projects and had to figure it out. But I think having something standardized that's built into the component itself would make it easier to implement and more future-proof

@David-Desmaisons
Copy link
Member

@madebycaliper what is your work-around?

@itaishopen
Copy link

itaishopen commented Mar 31, 2019

@David-Desmaisons I have a solution that works with some glitches
<draggable class="listgroup" :class="list._id" v-model="listArray" v-bind="dragOptionsCard" @EnD="funToMove">




listArray: this.cardList,

cardList() {
if (!this.list.cards && this.list.cards.length === 0) {
this.list.cards = []
}
return this.list.cards
},

if you have an empty list the function cardList in computed return an empty list for you to enter the cards in to.
in css i gave the empty list a min height of 50 px
.listgroup {
cursor: move;
min-height: 50px;
}

that fixed most of the bugs for me

@Doogiemuc
Copy link

I totally agree with madebycaliper: There should be a standard solution in Vue.draggable.
My "workaround" is working fine as far as I tested it: https://codepen.io/Doogie/pen/qvwjGE

@David-Desmaisons
Copy link
Member

@Doogiemuc I agree. Still looking for a reliable solution.

@madebycaliper
Copy link

@David-Desmaisons I often use Vuex to fire a DRAG_START and DRAG_END event and then map state and modify the dimensions of the empty Draggable using CSS. I've also tried :

  • a computed property somewhere in the component that recognizes when the list is empty and defaults the min-height to more than 0px
  • applying a min-height style at all times
  • used an::after{} CSS declaration to mock a "drag here" kind of region.

There are oviously lots of custom tactics available, but it would be great if you offered a standardized solution and some supporting logic.

@SirLamer I definitely like the idea of a named slot, as it would be optional and unobtrusive. If the Draggable component could just conditionally show that slot based on items.length, we could pass an element that would extend the list height if it's empty.

@johnbamlamb
Copy link

I have had some success using the header slot like this as the last element inside the draggable component:
<h3 slot="header" v-if="report.report_modules.length === 0" class="text-secondary">Drop modules here...</h3>

@MemeDeveloper
Copy link

I agree that a named slot would be ideal.

However, here's my v simple workaround that's bug free (for me) :

.list-group:empty {
    padding:1rem;
    text-align:center;
}

.list-group:empty:before {
    content: 'Drop files here';
}

This works with

<draggable class="list-group" etc...

@MemeDeveloper
Copy link

MemeDeveloper commented Aug 6, 2020

N.B. above doesn't seem to work when using a transition-group as this adds a span to the "empty" list, meaning the :empty selector doesn't get applied.

@MemeDeveloper
Copy link

I got transition-group working with modified css selector and tag="div" as per :

<transition-group type="transition" tag="div">

.list-group:empty,
.list-group > div:empty {
    padding:1rem;
    text-align:center;
}

.list-group:empty:before,
.list-group > div:empty:before {
    content: 'Drop files here';
}

i.e. add a second selector to target the empty div produced by the transition-group

Hope that helps someone out, and thanks for the awesome code !

@CheshireCaat
Copy link

Any updates?

@adamreisnz
Copy link

@David-Desmaisons this issue was first raised more than 3 years ago.
Is it possible to see if this can be implemented in the Vue 3 version?

It doesn't seem like an overly complicated problem to generate/create a cloned copy of the item that is being dragged and have it stay in the original position in the list.

A cloned (ghost) version is already being created, but it's being moved around depending on the mouse position. So another non-moving clone can be created to remain in place where the original item used to sit.

This will make sorting items in the list much calmer to look at as there won't be so much movement happening during the sorting of the item, and it would also fix the webkit hover bug which applies the hover class onto items that are positioned instead of the original item that's being dragged.

@simonj
Copy link

simonj commented Jan 1, 2022

+1 for this. This is the feature am working on where i want to have a bigger drag area

Skaermoptagelse.2022-01-01.kl.23.59.37.mov

@artemryskal
Copy link

I found a workaround for this webkit browsers bug. For every draggable element you need to add mouseover events which take setHoverEffect function.

setHoverEffect (event) {
  const childList = [].slice.call(event.currentTarget.parentElement.children)

  for (const child of childList) {
    child.classList.remove('hovered')
  }

  if( !childList.some((child) => child.classList.contains('sortable-chosen')) ) {
    event.currentTarget.classList.add('hovered')
  }
}
.hovered {
  background-color: orange;
  color: #fff;
}

Then you need to add mouseleave event which will remove hovered class.
event.currentTarget.classList.remove('hovered')

@CultivateCreate
Copy link

is this project still active? I see no resolution for this issue, so I'm assuming no?

@heavy-matill
Copy link

I found a CSS solution:
Add a dummy element in header (or Footer) element with class=hideable-header.
Add CSS:
.hideable-header:not(:only-child){ display: none; } .hideable-header:only-child{ display: block; }
This will result in the element only being shown if it is the only-child of its parent.

In case you have a header or footer already use :first-child or :last-child.

@Gyurmatag
Copy link

Any updates?

@abejordan
Copy link

How about doing this.

<Draggable class="list-group" :list="list" group="blocks" item-key="uuid">
  <template #header v-if="draft.length == 0">
    What you want to show when the list is empty
    </template>
  <template #item="{ element, index }">
    Your list
</template>
</Draggable>

This essentially hides the header slot when the list has more than 0 elements.

@georiv
Copy link

georiv commented Dec 13, 2024

Any updates on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests