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

Array.push() on the model breaks the model order #126

Closed
Danita opened this issue Apr 21, 2017 · 13 comments
Closed

Array.push() on the model breaks the model order #126

Danita opened this issue Apr 21, 2017 · 13 comments

Comments

@Danita
Copy link

Danita commented Apr 21, 2017

Hi! Loving Vue.Draggable so far, it has been amazing 😄

I'm having this bug where new array elements are not visually appended at the end when they have been added programmatically to the array (array.push()) after previously having swapped two items. It does not happen if previously the existing items are moved more than one position. See capture below:

image

As you can see, the order of the new item on the model is correct, but the UI is out of sync. It's been several hours and I cannot find a way to make the UI get in sync again with the model. I've tried on my handleAddOption() method to fiddle with the array on $nextTick so perhaps it could be refreshed, but no avail, and I ran out of ideas.

Am I doing something wrong? Thanks!

That section of the template looks like this:

<ul class="list-group">
	<draggable v-model="internalModel.col1" :options="draggableOptions">
		<li class="list-group-item list-group-item-editable canBeDragged"
			v-for="elemento, i in internalModel.col1"
			:key="elemento._temp_id"			
		>
			<div class="handle">
				<i class="fa fa-navicon"></i>
			</div>
			<div class="content">
				<input type="text" class="form-control" v-model="elemento.titulo"
					   :placeholder="'Texto de la opción ' + (i+1) +  ' columna 1...'">
			</div>
			<div class="actions">
				<i class="fa fa-trash-o" v-on:click="handleDeleteOption(elemento, 1)"></i>
			</div>
		</li>
		<li class="list-group-item list-group-item-add">
			<a href="javascript:" class="btn btn-success btn-sm" v-on:click="handleAddOption(1)">
				<i class="fa fa-plus mr10"></i>Agregar elemento
			</a>
		</li>
	</draggable>
</ul>

My model looks like this:

internalModel: { "id": 13, "col1": [ { "id": 1, "titulo": "Cuadrado", "nro_columna": 1, "_temp_id": "$temp1" }, { "id": 2, "titulo": "Pentágono", "nro_columna": 1, "_temp_id": "$temp2" }, { "id": 3, "titulo": "Triángulo", "nro_columna": 1, "_temp_id": "$temp3" }, { "id": 4, "titulo": "Hexágono", "nro_columna": 1, "_temp_id": "$temp4" } ], "col2": [ { "id": 5, "titulo": "3", "nro_columna": 2, "_temp_id": "$temp5" }, { "id": 6, "titulo": "5", "nro_columna": 2, "_temp_id": "$temp6" }, { "id": 7, "titulo": "4", "nro_columna": 2, "_temp_id": "$temp7" } ], "discr": "compitemevalapareamiento" }

And I'm instancing the draggable with these options:

export default {
	handle: '.handle',
	forceFallback: true,
	fallbackOnBody: true,
	animation: 150,
	draggable: '.canBeDragged'
}

New empty items are added like this

handleAddOption: function(col) {
	let newOption = {
		titulo: "",
		nro_columna: col,
		_temp_id: uniqueId(),
	};
	this.internalModel[`col${col}`].push(newOption);
},
@David-Desmaisons
Copy link
Member

Hi @Danita , there is something wrong with the draggable mark-up: draggable children should be only v-for elements. Somethong like this:

<ul class="list-group">
	<draggable v-model="internalModel.col1" :options="draggableOptions">
		<li class="list-group-item list-group-item-editable canBeDragged"
			v-for="elemento, i in internalModel.col1"
			:key="elemento._temp_id"			
		>
			<div class="handle">
				<i class="fa fa-navicon"></i>
			</div>
			<div class="content">
				<input type="text" class="form-control" v-model="elemento.titulo"
					   :placeholder="'Texto de la opción ' + (i+1) +  ' columna 1...'">
			</div>
			<div class="actions">
				<i class="fa fa-trash-o" v-on:click="handleDeleteOption(elemento, 1)"></i>
			</div>
		</li>
	</draggable>
	<li class="list-group-item list-group-item-add">
		<a href="javascript:" class="btn btn-success btn-sm" v-on:click="handleAddOption(1)">
			<i class="fa fa-plus mr10"></i>Agregar elemento
		</a>
	</li>
</ul>

If there does not solve the problem, please isolate the scanerio in a jsfidle and send the link here.

@Danita
Copy link
Author

Danita commented Apr 21, 2017

Hi, @David-Desmaisons, thanks for your quick reply!
I was just taking advantage of the draggable: '.canBeDragged' option of Sortable, but now that I see it, it was not really necessary. I'll try that markup and see what happens.

@Danita
Copy link
Author

Danita commented Apr 21, 2017

OMG thanks! That did the trick 😺 I guess I was too many hours in front of the monitor.

The only problem remaining is the extra <div> created inside the <ul> where the <draggable> element used to be. The generated DOM now looks like this:

<ul class="list-group sortable-container mb10">
	<div>
		<li id="$temp5" class="list-group-item list-group-item-editable canBeDragged">...</li>
		<li id="$temp6" class="list-group-item list-group-item-editable canBeDragged">...</li>
		<li id="$temp7" class="list-group-item list-group-item-editable canBeDragged">...</li>
	</div>
	<li class="list-group-item list-group-item-add">
		<a href="javascript:" class="btn btn-success btn-sm">...</a>
	</li>	
</ul>

Which causes a rendering artifact. Is there any way to remove it?

@David-Desmaisons
Copy link
Member

@Danita , I would consider using element props and take-out the add button from the the ul. Like this:

<div>
  <draggable element="ul" class="list-group" v-model="internalModel.col1" :options="draggableOptions">
	<li class="list-group-item list-group-item-editable canBeDragged"
			v-for="elemento, i in internalModel.col1"
			:key="elemento._temp_id">		
	
			<div class="handle">
				<i class="fa fa-navicon"></i>
			</div>
			<div class="content">
				<input type="text" class="form-control" v-model="elemento.titulo"
					   :placeholder="'Texto de la opción ' + (i+1) +  ' columna 1...'">
			</div>
			<div class="actions">
				<i class="fa fa-trash-o" v-on:click="handleDeleteOption(elemento, 1)"></i>
			</div>
		</li>
	</draggable>
	<div class="list-group-item list-group-item-add">
		<a href="javascript:" class="btn btn-success btn-sm" v-on:click="handleAddOption(1)">
			<i class="fa fa-plus mr10"></i>Agregar elemento
		</a>
	</div>
</div>

That will render:

<div>
   <ul class="list-group sortable-container mb10">	
	<li id="$temp5" class="list-group-item list-group-item-editable canBeDragged">...</li>
	<li id="$temp6" class="list-group-item list-group-item-editable canBeDragged">...</li>
	<li id="$temp7" class="list-group-item list-group-item-editable canBeDragged">...</li>
  </ul>
	<div class="list-group-item list-group-item-add">
		<a href="javascript:" class="btn btn-success btn-sm">...</a>
	</div>	
</div>

@Danita
Copy link
Author

Danita commented Apr 21, 2017

Ah I understand, but the whole point is the Add button needs to be part of the list. No problem, I'll figure out, thanks again for your help! 😄

@David-Desmaisons
Copy link
Member

Thanks for the feedback, I am closing the issue.

@lbjones
Copy link

lbjones commented Jun 15, 2017

I also am having this problem. If you can explain how you figured it out (if you did) it would be appreciated! Otherwise I've got to think this issue is a bug.

@Danita
Copy link
Author

Danita commented Jun 16, 2017

@lbjones I left the markup as per @David-Desmaisons' example, the button outside the draggable elements. The draggable option of Sortable doesn't work in the context of this library.

<div>
  <draggable element="ul" ...>
    <li v-for="elemento, i in internalModel.col1" ...>		
    ...
    </li>
  </draggable>
  <div>
    <a class="btn" ...></a>
  </div>
</div>

@lbjones
Copy link

lbjones commented Jun 17, 2017

Darn I was afraid of that! Pulling the last element out of the draggable really ruins the UI for me.

@David-Desmaisons
Copy link
Member

David-Desmaisons commented Jun 24, 2017

@Danita and @lbjones I just released version v2.14.0 that supports footer slot. It adresses your original problem: adding a none-draggable item inside a draggable component

@Danita
Copy link
Author

Danita commented Jun 26, 2017

@David-Desmaisons Good to know, I'll try it soon. Thanks!! <3

@lbjones
Copy link

lbjones commented Jun 27, 2017

Just tried it, works like a charm! You are the man @David-Desmaisons

@davidivab
Copy link

Hola @Danita vi tu esquema con Vue.Draggable y resolviste algo que llevo mucho tiempo intentando, mi ejercicio es tener una lista y clonar sus elementos en varias listas, sin embargo no he podido eliminar los elementos clonados en las otras listas y además no sé como hacerlo sin que se borre el elemento de la lista principal, únicamente quiero borrarlo de la lista a la cual pertenece. Si tienes alguna idea de como resolverlo te lo agradecería mucho. Mil gracias

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

No branches or pull requests

4 participants