Skip to content
This repository has been archived by the owner on Feb 1, 2022. It is now read-only.

Select nested child elements #6

Open
Grawl opened this issue Aug 25, 2017 · 11 comments
Open

Select nested child elements #6

Grawl opened this issue Aug 25, 2017 · 11 comments

Comments

@Grawl
Copy link

Grawl commented Aug 25, 2017

I tried to select <g> inside SVG inside my Vue app, but when I tried to console.log(el) in isItemSelected method, I just see <svg> element in colsole.

@stephan281094
Copy link
Owner

Hi there! Have you applied the CSS 'selectorClass' class to the <g> elements?
Could you perhaps show me some code?

@Grawl
Copy link
Author

Grawl commented Sep 4, 2017

I use vue-drag-select like this gist and import it using Rollup:

import dragSelect from './vendor/vue-drag-select'
const app = new Vue({
	el: '#hallApp',
	components: {
		'drag-select-container': dragSelect
	}
})

And I put my SVG right into template, inline:

<div id="hallApp">
	<drag-select-container selectorClass="cls-1">
		<template scope="{ selectedItems }">
			<svg xmlns="http://www.w3.org/2000/svg" viewBox="6602.848 -554.785 878.112 543.45">
				<g id="Group_1089" transform="translate(-957.152 -3588.785)">
					<g id="Rectangle_1128" class="cls-1" data-sector="pew-2" data-row="row-1"
					   data-seat="0" transform="translate(7812.659 3529.023)">
						<rect class="cls-7" width="10.221" height="10.221"/>
						<rect class="cls-8" x="0.1" y="0.1" width="10.021" height="10.021"/>
					</g>
				</g></svg>
		</template>
	</drag-select-container>
</div>

It's a map of a concert hall. I handle clicks on elements with [data-seat] attribute and use data-attributes to do some, it works.

I want to select a multiple <g class="cls-1"> elements using vue-drag-select.

I added console.log(el) to isItemSelected method to debug this and I see that el is an <svg> element when I drag to select some elements.

If I use regular HTML elements into <template>, it works properly:

<template>
	<drag-select-container selectorClass="cls-1">
		<template scope="{ selectedItems }">
			<div class="cls-1"></template>
	</drag-select-container>
</template>

In that case, isItemSelected shows me how many <div class="cls-1"> is selected.

@stephan281094
Copy link
Owner

Hi there! Thanks for demonstrating me your code. The reason why it's not working is because Vue Drag Select only looks one level deep for children. Since the drag-select-container is defined as a parent of svg, the only child it can find is svg.
Therefore this is not a bug related to SVG, but rather to nested children.

A potential solution to this problem is to recursively look for children, though I'm not sure if that's a good idea.

@stephan281094 stephan281094 changed the title Select SVG elements Select nested child elements Sep 4, 2017
@Grawl
Copy link
Author

Grawl commented Sep 4, 2017

Why you think it's a bad idea? In that case, performance is due to library user, not on a library itself. You requires CSS class name for child elements, and it's obvious must be equal to CSS selector query. I see it like drag-select-container .cls-1, so if you mean drag-select-container > .cls-1 you must specify it in documentation.

@stephan281094
Copy link
Owner

I agree. Let's refactor the code to allow nested child elements.

@stephan281094
Copy link
Owner

Unfortunately no, nested child elements are currently not supported. Feel free to send a pull request, though!

@JochenLutz
Copy link

I need to select rows in a table build with BootstrapVue's b-table.
I have a working solution in my fork. I added a function property that returns the items to work on. It works for me, but I'm not sure it's generic for all use cases. I also added a select event triggered only on onMouseUp.
Is this approach worthy a PR? If yes, what is missing (apart from documentation)?

Usage

<drag-select selectorClass="selectable" :selectorFunction="selectableItems">
  <template slot-scope="{ selectedItems }">
    <b-table :items="items" tbody-tr-class="selectable">
    </b-table>
  </template>
</drag-select>

[…]

methods: {
  selectableItems() {
    return this.$el.getElementsByTagName('tr')
  }
}

@stephan281094
Copy link
Owner

Hi Jochen, thanks for showing interest in this project!

Having a more composable way of defining the selectable items is definitely a better solution. Doing it this way, we should be able to get rid of the whole selectorClass property and make vue-drag-select smarter when it looks for elements that are 'selected'.

In my opinion, a more intuitive approach to this would be to define a property selectableItems that's simply an array of DOM elements. We can then simply check if the selected elements are in this array, or if they are a child of one of the elements in the array.

If we can get that to work properly, I'm definitely open to pull requests!

@JochenLutz
Copy link

JochenLutz commented May 16, 2019

Ok, good to know you are open to greater changes.
I removed selectorClass.
Passing the items as array does not work in my case, because the <b-table> is a child node of <drag-select>, so I also support a function returning the array of items. I kept the usage of the child nodes as default if no items are passed explicitly. This fallback still uses Vue components if available instead of DOM nodes as I'm not sure of that feature's use cases.
Still missing documentation.
Does this meet your idea of more composable? Should I open a PR?

@daliborjelinek
Copy link

Hi, I would really appreciate this functionality. @stephan281094 Are you planning accept this pull request and release new version?

@joycelacey
Copy link

@JochenLutz I am also looking to use this with BootstrapVue's b-table and took a look at your fork and I'm interested in using the changes you made, but having a little trouble wrapping my brain around how you get b-table to recognize what was selected. Could you post a codepen of how you got that part to work?

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

No branches or pull requests

5 participants