ratiw / vuetable-2

data table simplify! -- datatable component for Vue 2.x. See documentation at
https://vuetable.com
MIT License
2.16k stars 399 forks source link

Send props to custom action component #14

Open adifaidz opened 8 years ago

adifaidz commented 8 years ago

Currently I've defined a component in a file :

<template lang="html">
  <div class="btn-group" role="group" aria-label="...">
    <a @click="onShow(rowData)" class="btn btn-info"><i class="fa fa-info"></i>&nbsp;Detail</a>
    <a @click="onEdit(rowData)" class="btn btn-primary"><i class="fa fa-edit"></i>&nbsp;Edit</a>
    <a @click="onDelete(rowData)" class="btn btn-danger"><i class="fa fa-trash"></i>&nbsp;Delete</a>
  </div>
</template>

<script>
export default {
  props: {
    rowData: {
      type: Object,
      required: true
    },
    showUrl: {
      type: String,
      required: true
    },
    editUrl: {
      type: String,
      required: true
    },
    deleteUrl: {
      type: String,
      required: true
    },
    redirectUrl: {
      type: String,
      required: false
    }
  },
  methods: {
    onShow: function(data) {
      window.location.href = this.showUrl + '/' + data.id
    },
    onEdit: function(data) {
      window.location.href = this.editUrl + '/' + data.id
    },
    onDelete: function(data) {
      this.$http.delete(this.deleteUrl + '/' + data.id).then(
        (response) => {
          console.log(response);
          if(this.redirectUrl !== undefined)
            window.location.href = this.redirectUrl

          this.$parent.refresh()
        },
        (response) => {
          console.log(response);
        }
      )
    }
  }
}
</script>

Is there anyway to send props to my component ? Currently I see only a way to state which component to be used for the __component column without sending it anything. Please help 🙏

ratiw commented 8 years ago

@adifaidz Technically, this could be done by sending additional object to the component. But this will lack the prop validation provided by Vue.js. Let me think about it and I'll let you know.

adifaidz commented 8 years ago

Thanks a lot, really hoping this could be done 😄

ratiw commented 7 years ago

@adifaidz Would you mind telling me what kind of prop you would like to send to the __component?

I start to think about this problem and there seems to be many possible solutions but cannot decide which way to go as I do not really have a valid use case for it.

wanlxp commented 7 years ago

me too, really hoping this could be done :smile:

adifaidz commented 7 years ago

@ratiw I kinda wanna send urls to the component, because my component remains the same for every page except for the url. Right now what I'm doing is instantiating an object before the vue import

var params = {
      url : {
        show: '{{route('admin.role.show', ['id' => null])}}',
        edit: '{{route('admin.role.edit', ['id' => null])}}',
        delete: '{{route('admin.role.destroy', ['id' => null])}}'
      }
}

And assigning it to the component data like so,

data(){
  return{
    showUrl: params.url.show,
    editUrl: params.url.edit,
    deleteUrl: params.url.delete,
    redirectUrl: params.url.redirect
  }
},
methods: {
  onDelete: function(data) {
    this.$http.delete(this.deleteUrl + '/' + data.id).then(
      (response) => {
        console.log(response);
        if(this.redirectUrl !== undefined)
          window.location.href = this.redirectUrl
       this.$parent.refresh()
      },
      (response) => {
        console.log(response);
      }
    )
  }
}

It works but its kinda an ugly hack if you ask me 😞. Sorry it took me so long too reply to this, was caught up in some work lol

ratiw commented 7 years ago

@adifaidz @wanlxp I find that using event is actually more convenient and less hacky. In this case, I'm using vue-events to be the centralized event hub.

    npm install vue-events@vue-2.x
    import Vue from 'vue'
    import VueEvents from 'vue-events'

    Vue.use(VueEvents)

In you custom component, you detect what the user want and then fire the appropriate event to the centralized event hub.

    // CustomAction.vue
    <template>
        <div class="btn-group" role="group" aria-label="...">
            <a @click="onAction('show-item', rowData)" class="btn btn-info"><i class="fa fa-info"></i>&nbsp;Detail</a>
            <a @click="onAction('edit-item', rowData)" class="btn btn-primary"><i class="fa fa-edit"></i>&nbsp;Edit</a>
            <a @click="onAction('delete-item', rowData)" class="btn btn-danger"><i class="fa fa-trash"></i>&nbsp;Delete</a>
        </div>
    </template>
    <script>
    export default {
        //...
        methods: {
            onAction: function(action, data) {
                this.$event.fire(action, data)
            }
        }
    }
    </script>

Then, in your main app or component you can listen to those events and act accordingly. In this case, vue-events allow you to register event listeners in the events section, just like in Vue 1.x

    <template>
        //...
        <vuetable ref="vuetable"
            //...
        ></vuetable>
        //...
    </template>
    <script>
    export default {
        //...
        methods: {
            //...
        },
        //...
        events: {
            'show-item': function(data) {...},
            'edit-item': function(data) {...},
            'delete-item': function(data) {...}
        }
    }
    </script>
adifaidz commented 7 years ago

@ratiw Hmm, this looks clean enough. Never thought of it that way though 👍. I'll test this out and get back to you on this.

adifaidz commented 7 years ago

@ratiw I feel using events is the way to go for handling events in the component, but lets say that I have a multiple wrapper component for vuetable, wouldn't this make it tightly coupled with the component?

If I were to have an action component with other event names, that means that the wrapper must register listeners for all the possible events. I know it seems a bit of a stretch as it seems unlikely to have so many events but it would be better to have the flexibility.

Also, I think another case of sending props to the component would be if I want to hide a component button based on a prop. Can it be achieved using events too? Would any problem arise?

For now I'm going with events as it's clearly the best way available now 😃👍

ratiw commented 7 years ago

@adifaidz I wouldn't worry too much about coupling now as I used to.

When it comes to actual app development, you can only think so much. But all of that wouldn't mean so much until you actually start doing it. Then, you would really see the what you think is correct or not. And all of that wouldn't matter at all if the app does not finish in time.

You just have to make it possible for you to come back at what you feel is not right and rework on it. That's where writing tests come in. Without the test, I can almost guarantee that you will lost the will to come back and refactor it.

In my opinion, using event is actually make it less couple and simplifying codes. One component can emit as many event as it wants, but you only listen to the events you're interested and act on them.

I believe that setting props are mostly for the initialization step (that's why in Vue 2.x you should not mutate the prop value inside your component, in my opinion) and later any communication to the component should be done via events.

I think you can do almost anything using event. You just have to be clear what and when you want your component to do when the events it is listening comes.

I have tried various ways to allow passing additional parameter to the component, but event seems to be the best for its simplicity and clearity.

sjmarve commented 7 years ago

@ratiw This might solve your issue. https://github.com/ratiw/vuetable-2/pull/46

redgluten commented 6 years ago

Both these solutions seem excessively complex to just pass a simple string to the __component, especially when you only need to define the url. In my case these are regular, old-school links that redirect to a resource form.

@ratiw Any clue how to do that?

P.S: thanks for the work on this package 👍.