How to call a function when a SyncFusion grid row is selected - vue.js

Using a SyncFusion Vue Grid component, I need to call a function when a row is selected. I have tried adding a column of edit buttons but I can't find documentation for the correct syntax to use to get the buttons to call a function. I also tried looking for a way to just call a function whenever the row itself is clicked which would be fine as long as I can determine which row was clicked (access the value of one of the fields in the row). The Grid Selection API looks like it is just for programmatically selecting parts of the grid which is not what I am trying to do. I tried following this explanation but I could not figure out the syntax for getting the button to call a function. I have looked at the Vue and SyncFusion documentation but I can't find specifically what I am trying to do. Below are the relevant parts of the code.
<template>
<ejs-grid>
<e-columns>
<e-column
headerText='Buttons'
width='120'
:template='cTemplate'></e-column>
<e-column
field="name"
headerText="Name"
:isPrimaryKey="true"
width="60"
></e-column>
<e-column
field="generalSubject"
headerText="Subject"
width="40"
></e-column>
</e-columns>
</ejs-grid>
</template>
<script>
export default Vue.extend({
data() {
cTemplate: function () {
return { template : Vue.component('columnTemplate',{
template: `<button v-on:click="fx">Edit</button>`, // <-- call fx() syntax??
data: function() {
return {
data: {}
}
},
})}
},
fx: function() { // do something },
},
});
</script>

Your requirement can be achieved by using the Grid’s rowSelected event. This event gets triggered on selecting a Grid row and returns the current row details in the event arguments.
Please find the below sample prepared based on this for your reference,
Sample: https://codesandbox.io/s/vue-forked-0knlb?file=/src/App.vue
API link: https://ej2.syncfusion.com/vue/documentation/api/grid/#rowselected
Let us know if you need further assistance.
Regards,
Sujith R

Related

How to solve filtered API results in Vue app returning undefined?

As a newbie I’m trying to get my head around Vue and I’m having difficulty with the functionality of my Github jobs api app. The full project can be viewed here https://codesandbox.io/s/modest-banach-u6fzg
I’m having issues with the filtering of the api results, in particular the ‘load more’ button which, ideally, will filter the results of the api into batches of 10. The issues are:
The load more function works initially, but once there are, say, 30 results displayed on the app, the search function at the top does not work.
The search function works on the initial render of the page with 10 results being displayed, but the ‘load more’ button/function does not work on the returned results. As an example, if you search for ‘UK’ in location you get an initial 10 results, but a console.log reveals that there are 50 results returned from the api, which come back as undefined so are not displayed.
I’m not sure if these two problems are linked to a single issue.
Any advice would be much appreciated, as well as any feedback on how I’ve implemented the app.
Thanks!
Mike
You need to use computed prop instead of a function and you also you should reset loaded items counter if jobs loaded again.
See modified code
<template>
<div v-if="jobs.length">
<div v-for="job in filterJobs" v-bind:key="job.id">
<!-- <div v-for="job in jobs" v-bind:key="job.id"> -->
<Job v-bind:job="job" />
</div>
<button v-on:click="loadMore">Load More</button>
</div>
</template>
<script>
import Job from "./Job";
export default {
name: "Jobs",
components: {
Job,
},
data() {
return {
jobCount: 10,
};
},
props: ["jobs"],
watch: {
// watcher to reset a counter
jobs(newValue, oldValue) {
this.jobCount = 10;
},
},
computed: {
// computed prop instead of function, that way it would be reactive
filterJobs() {
return this.jobs.slice(0, this.jobCount);
},
},
methods: {
loadMore() {
// we need to check if we are exceeding a length of jobs array or not
if (this.jobCount + 10 <= this.jobs.length) {
this.jobCount += 10;
} else {
this.jobCount = this.jobs.length;
}
},
},
};
</script>
<style lang="stylus" scoped></style>

How to use Vue Router programatically with native events?

I have been trying to use native events with Vue router using this.$router.push and I keep producing the following error:
[Vue warn]: Invalid handler for event "click": got undefined
found in
---> <section>
I can't seem to figure out why and I have to use multiple solutions, all of which produce the above error. Some of them redirect to the page directly before triggering the event.
Things that I have tried:
1.
//in JSX
<section nativeOnClick={this.navigationPage('login')}></section>
// in methods I have the following:
methods: {
navigationPage: function (page) {
this.$router.push(page)
}
}
2.
//in JSX
<section nativeOnClick={this.$router.push('login')}></section>
One solution that works is the following:
//in JSX
<section nativeOnClick={this.navigateToLogin}></section>
// in methods I have the following:
methods: {
navigateToLogin: function () {
this.$router.push(page)
}
}
Could you please let me know what I am doing wrong in 1 and 2. The solution that works is fine but that requires me to create a method for every navigation. I personally like 2!!
Any help is appreciated
NEW
Below is the full component definition:
//navbar.js
import styles from './index.styl'
import logo from 'Src/assets/logo.svg'
import menu from 'Src/assets/menu.svg'
export default {
name: 'NavBar',
methods: {
navigationPage: function (page) {
this.$router.push(page)
}
},
render (h) {
return (
<ui-nav class={styles.nav}>
<ui-section class={styles.navLogo} nativeOnClick={ this.navigationPage('hello') }>
<ui-image source={logo} />
</ui-section>
<ui-spacer />
<ui-section class={styles.navMenu}>
<ui-image source={menu} />
</ui-section>
</ui-nav>
)
}
}
Note: This style also automatically navigates to /hello (i.e. before click event). I do not know why.
Have you tried removing the this reserved word from your jsx native invocation?, for example:
<section nativeOnClick={ navigationPage('login') }></section>
If you can you post the whole script of your single file component (or whatever you are editing) would be helpful for me to be in context.
It looks like there is one solution that works, but I can't understand why it works though!
working solution:
<section nativeOnClick={ () => this.$router.push('hello') }></section>
The thing that is confusing is why passing arguments without the handler produces the error by when wrapping with a function it does not.
i.e
<section nativeOnClick={ this.$router.push('hello') }></section> // GIVES error

How i can use a router-link in kendo grid (vuejs)

How i can use <router-link to="/detail/1">Details</router-link> with Kendo Grid?
I want use the standard logic of a normal link in the grid, with no reload of the full page on click. I have try to use router-link inside the grid with a template but it's doesn't work. Also no error in available in console.
Example on Stackblitz
Update 24 October 2018
Kendo Grid for Vue is initializing a plain Kendo Grid widget for jQuery.
Thus, all templates are evaluated runtime and possible routes cannot be evaluated afterwards or the router-link elements to be resolved.
If you have the same problem Vote for this suggestion
vue native implementation
It is true that you cannot use router-link inside a kendo template. But I thought I would offer an alternative way to achieve the same result.
You can redirect to the new page using the programmatic way by calling router.push({ path:/detail/${id}}).
Replace the template with a command that implements a click event, and call route.push from there.
I have updated your example on slackblitz with a working example.
Kendo Grid with command col
<kendo-grid ref="grid"
:height="550"
:data-source-ref="'datasource1'"
:sortable="true">
<kendo-grid-column :field="'ProductID'"
:title="'Product ID'"></kendo-grid-column>
<kendo-grid-column :field="'ProductName'"
:title="'Product Name'"></kendo-grid-column>
<kendo-grid-column :field="'Link'" :template="linkTemplate1"></kendo-grid-column>
<kendo-grid-column :command="detailsLink"></kendo-grid-column>
</kendo-grid>
Command array in the data object.
new Vue({
el: '#vueapp',
router,
data () {
return {
linkTemplate1: "<a href='/detail/#:ProductID#' class='k-button'>Link</a>",
detailsLink: [{
name: "details",
click: function(e) {
// prevent page scroll position change
e.preventDefault();
var tr = $(e.target).closest("tr"); // get the current table row (tr)
// get the data bound to the current table row
var data = this.dataItem(tr);
// redirect to new page
router.push({ path: `/detail/${data.ProductID}` })
},// template must include k-grid-[command name]
template: "<a class='k-button k-grid-details'>TEST</a>"
}]
}
}
})

Multiple instances of a vue.js component and a hidden input file

I am experiencing a weird behavior using Vue.js 2.
I have a component that I reference twice in a single html page.
This component contains an input file control called attachment_file. I hide it using the Bootstrap class hidden and I open the file selection using another button. When a file is selected, I put in a variable called attachment_filename a certain string just like so:
<template>
<div>
<button #click="selectAttachement"><span class='glyphicon glyphicon-upload'></span></button>
<input id="attachment_file" type="file" class="hidden" #change="attachmentSelected">
{{attachment_filename}}
</div>
</template>
<script>
export default {
data () {
return: {
attachment_filename: null,
}
},
methods: {
selectAttachement () {
$('#attachment_file').click();
},
attachmentSelected () {
this.attachment_filename = 'some file here';
},
}
}
</script>
Problem With the class hidden and when a file is selected from the 2nd instance of the component, the value of this.attachment_filename is updated but in the data of 1st instance of the component!
If I remove the class hidden, it updates the value in the correct instance.
Possible solution use css opacity or width instead of the class hidden.
But is there a reason for this behavior?
Not sure why it is not working specifically with .hidden, but you have an inherent problem in the code that i think is the cause of the problem.
You are selecting the input using jquery with an id, that creates a couple of problems:
When you use the component twice or more, all these inputs generated by these components will have the same id, which is not what you want since id should be unique
Even if you change it to a class instead of id, it won't work properly since you are selecting the element using jquery, and that will select all the elements with this class, while you want to select just the input in that component.
The solution is to use refs:
<input id="attachment_file" type="file" class="hidden" #change="attachmentSelected" ref="fileInput">
selectAttachement () {
$(this.$refs.fileInput).click();
},

Event handlers and components in vue.js

How would I specify a kind of change/input handler to be used by a component in vue.js, when I already have one in place in the component? I have a text input which in very simplified form is akin to this:
Vue.component('text-input', {
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
' ,
props: ['value'],
methods: {
updateValue: function (value) {
this.$emit('input', value);
},
uppercase:function(value){
return value.toUpperCase();
}
}
});
I would use it like this:
<text-input v-model="name"></text-input>
It works fine, and updates correctly using the events system (with $emit). But now I want to convert the entered value to uppercase, so would presumably want to pass in an input handler which is the name of the method, such as 'uppercase', in my 'text-input' component. So I would have this:
<text-input v-model="name" #input="uppercase"></text-input>
But within my component, #input is already used by updateValue. How can I combine the two? (Or, perhaps, is there a different and better way of thinking this whole problem?)
I'm having a bit of a hard time following, but if you wanted to run two functions on the same event you can just do two things in one function.
#input="update"
Then something like:
update: function (event) {
this.updateValue(event.target.value)
this.somethingElse()
}
Though, if the code you have is really what you're trying to do you can do:
this.$emit('input', this.uppercase(value))
After discussing a bit more in the comments. You can pass a custom callback as a property if you'd like and call that instead of whatever the default is. Here's a quick fiddle of one way to approach that: https://jsfiddle.net/crswll/3xwmgpom/