Sort table Vue.js - sorting

I am trying to sort a table by columns. That when pressing the ID button all the column is ordered from highest to lowest or vice versa, and the same by pressing the other two. How can I do it?
<table id="mi-tabla">
<thead>
<tr class="encabezado-derecha" >
<th>ID</th>
<th>Nombre de sección</th>
<th>Potencial (€)</th>
</tr>
</thead>
<tbody>
<tr class="item" v-for="user in userInfo" #click="openDiv(), showInfo1(user.id_section)">
<td>{{user.id_section}}</td>
<td>{{user.desc_section}}</td>
<div class="acceder">
<td>{{user.sale_potential | currency}}</td>
<img src="../../iconos/icon/chevron/right#3x.svg" alt />
</div>
</tr>
</tbody>
</table>
{
"id_store": 4,
"id_section": 1,
"desc_section": "MATERIALES DE CONSTRUCCION yeh",
"id_rule": 1,
"sale_potential": "69413.5525190617"
},
{
"id_store": 4,
"id_section": 2,
"desc_section": "CARPINTERIA Y MADERA",
"id_rule": 1,
"sale_potential": "74704.3439572555"
},
{
"id_store": 4,
"id_section": 3,
"desc_section": "ELECTR-FONTAN-CALOR",
"id_rule": 1,
"sale_potential": "101255.89182774"
}
]

Here's what it might look like if you want to implement yourself, note that this is very basic functionality and as you start to add additional features, you might see more benefit from using a component that already does it all.
Anyhow, the way you can do it is by using a computed (sortedList) to store a sorted version of the array. Then use another data variable to store which column you want to store by (sortBy), and optionally, you can store a sort direction (sortOrder)
then add a sort method that passes the sort key and updates the sortBy value and/or the sortOrder. When either of these values (or even the source array) changes, the computed will re-sort the array using the sort function.
new Vue({
el: "#app",
data: {
sortBy: "id_section",
sortOrder: 1,
userInfo: [
{
"id_store": 4,
"id_section": 1,
"desc_section": "MATERIALES DE CONSTRUCCION yeh",
"id_rule": 1,
"sale_potential": "69413.5525190617"
},
{
"id_store": 4,
"id_section": 2,
"desc_section": "CARPINTERIA Y MADERA",
"id_rule": 1,
"sale_potential": "74704.3439572555"
},
{
"id_store": 4,
"id_section": 3,
"desc_section": "ELECTR-FONTAN-CALOR",
"id_rule": 1,
"sale_potential": "101255.89182774"
}
]
},
computed: {
sortedList() {
return [...this.userInfo]
.map(i => ({...i, sale_potential:parseFloat(i.sale_potential)}))
.sort((a,b) => {
if (a[this.sortBy] >= b[this.sortBy]) {
return this.sortOrder
}
return -this.sortOrder
})
}
},
methods: {
sort: function(sortBy){
if(this.sortBy === sortBy) {
this.sortOrder = -this.sortOrder;
} else {
this.sortBy = sortBy
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
[{{sortBy}}] [{{sortOrder}}]
<table id="mi-tabla">
<thead>
<tr class="encabezado-derecha">
<th #click='sort("id_section")'>{{ sortBy === 'id_section' ? '*' : '' }}ID</th>
<th #click='sort("desc_section")'>{{ sortBy === 'desc_section' ? '*' : '' }}Nombre de sección</th>
<th #click='sort("sale_potential")'>{{ sortBy === 'sale_potential' ? '*' : '' }}Potencial (€)</th>
</tr>
</thead>
<tbody>
<tr class="item" v-for="user in sortedList">
<td>{{user.id_section}}</td>
<td>{{user.desc_section}}</td>
<div class="acceder">
<td>{{user.sale_potential | currency}}</td>
<img src="../../iconos/icon/chevron/right#3x.svg" alt />
</div>
</tr>
</tbody>
</table>
</div>

I would recommend you to use bootstrap Vue tables which come with filtering and sorting. All you have to do is pass your data to the table.
Here is a link you can check it out.
https://bootstrap-vue.js.org/docs/components/table#complete-example
< script >
export default {
data() {
return {
items: [{
"id_store": 4,
"id_section": 1,
"desc_section": "MATERIALES DE CONSTRUCCION yeh",
"id_rule": 1,
"sale_potential": "69413.5525190617"
},
{
"id_store": 4,
"id_section": 2,
"desc_section": "CARPINTERIA Y MADERA",
"id_rule": 1,
"sale_potential": "74704.3439572555"
},
{
"id_store": 4,
"id_section": 3,
"desc_section": "ELECTR-FONTAN-CALOR",
"id_rule": 1,
"sale_potential": "101255.89182774"
}
],
fields: [{
key: 'id_store',
label: 'id',
sortable: true
}, {
key: 'desc_section',
label: 'Nombre de sección'
}, {
key: 'sale_potential'
},{key:'actions'}]
}
},
} <
/script>
<b-table striped hover :items="items" :fields="fields">
<template v-slot:cell(sale_potential)="row">
<p>{{row.item.sale_potential |currency}}</p>
<img src="../../iconos/icon/chevron/right#3x.svg" alt />
</template>
<template v-slot:cell(actions)="row">
<button #click="openDiv(); showInfo1(row.item.id_section);"
class="btn" variant="primary">Action</button>
</template>
</b-table>

If you want to add this functionality yourself you can achieve it using a computed value to sort your data.
data () => ({
...
sortBy : null,
}),
computed : {
userInfoSorted () {
const sortBy = this.sortBy
if (!sortBy) return this.userInfo
return this.userInfo.sort((a,b)=> a[sortBy] > b[sortBy] ? 1 : -1)
}
}
Then update your sortBy value within the <th> tags in your template:
<th #click="sortBy='id_section'">ID</th>
and link your rows to the computed value:
<tr class="item" v-for="user in userInfoSorted">
EDIT: CHANGE SORT ORDER
To add an option to toggle the order, start by adding the headers to your data object:
data () => ({
...
headers : {
id_section : {
text : 'ID',
reverse : true
}
}
})
Then update your template to also change the reverse value on click:
<th v-for="(val,key) in headers" #click="sortBy=key; val.reverse=!val.reverse">
{{ val.text }}
</th>
Finally include the reverse value in your sort function:
userInfoSorted () {
const sortBy = this.sortBy
const r = this.headers[sortBy].reverse ? -1 : 1;
if (!sortBy) return this.userInfo
return this.userInfo.sort((a,b)=> a[sortBy] > b[sortBy] ? 1*r : -1*r)
}

Related

Anyone can tell me whats wrong in here when im putting a array of number like :1,2 its starting to freeze the screen i hope someone can help me thanks

Hello guys im trying to learn vue and im trying to use datatable from https://datatables.net/ and having a problem with my action button that im not able to get the id when the #viewModal is been triggered i hope someone can help me to get the id of each buttons thanks and here is my code TIA:
EmployeeDataTable Component :
<template>
<div class="card">
<div class="card-header">
<div class="card-title">Employee List</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table
id="employee-table"
class="table-sm table-bordered table-hover text-center display"
width="100%"
>
<thead>
<tr>
<th class="pt-3 pb-3">#</th>
<th>Name</th>
<th>Address</th>
<th>Contact #</th>
<th>Department</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</template>
<script>
//For Datatable to work
import "datatables.net";
import EmployeeEdit from "./EmployeeEdit.vue";
export default {
name: "EmployeeList",
data() {
return {
employees: [],
};
},
mounted() {
this.getEmployeeLists();
},
components: {
"employee-edit": EmployeeEdit,
},
methods: {
getEmployeeLists() {
// INITIALIZE DATATABLE
$("#employee-table")
.DataTable({
//LOADING
// processing: true,
//AJAX
serverSide: true,
//DIRECTION
order: [[1, "desc"]],
//AJAX
ajax: {
url: "/api/getEmployeeLists",
dataList: "json",
type: "POST",
data: { _token: "{{csrf_token()}}" },
},
//TABLE COLUMNS SHOULD BE THE SAME IN CONTROLLER
columns: [
{ data: "#" },
{ data: "name" },
{ data: "address" },
{ data: "contact" },
{ data: "department" },
{ data: "status" },
{
data: "actions",
//allowing modification
createdCell(cell, cellData, rowData) {
let EmployeeListDataTableActions = Vue.extend(
require("./EmployeeListDataTableAction.vue").default
);
let instance = new EmployeeListDataTableActions().$mount();
$(cell).empty().append(instance.$el);
},
},
],
//View Count in Table
lengthMenu: [
[10, 25, 50, -1],
[10, 25, 50, "All"],
],
})
.columns();
},
beforeDestroy: function () {
$(this.$el).DataTable().destroy();
},
},
};
</script>
EmployeeDataTableAction Component :
<template>
<button class="btn btn-primary btn-sm" #click="viewModal" title="View Employee Details">
<i class="fa fa-eye"></i>
</button>
</template>
<script>
export default{
name: 'EmployeeListDataTableAction',
data: function() {
return {
}
},
mounted() {
},
methods: {
viewModal() {
var id = $(this.$el).closest('tr').find('input').val();
return false;
axios
.post(`/api/getEmployeeDetails/${id}`, {
id: id,
})
.then((response) => {
$("#edit-employee-modal").modal("show");
$(".myModalLabel").text(
response.data.name +
" - " +
response.data.department_name
);
state.commit("getEmployeeDetailsArray", response.data);
state.commit("getTransactionId", response.data.id);
})
.catch((response) => {
this.$toast.top("Something went wrong!");
});
},
},
}
</script>
Employee Controller for the DataTable :
public function employeeList(Request $request){
$all = Employee::getEmployeeTotal();
//total count of data
$total_data = $all;
//total filter
$total_filtered = $total_data;
//set_time_limit(seconds)
$limit = $request->input('length');
//start
$start = $request->input('start');
//order
// $order = $columns[$request->input('order.0.column')];
//direction
$dir = $request->input('order.0.dir');
$search_value = $request->input('search.value');
if (!empty($search_value)) {
$posts = Employee::getEmployeeNameSearch($search_value,$start, $limit, $dir);
$total_data = count($posts);
$total_filtered = $total_data;
}else{
if(empty($request->input('search.value')))
{
//if no search
$posts = Employee::getEmployeeList($start, $limit, $dir);
}
}
$data = array();
if(!empty($posts))
{
$counter = $start + 1;
foreach ($posts as $post)
{
$department = GlobalModel::getSingleDataTable('departments',$post->department_id);
$status = StatusController::checkStatus($post->status);
$nested_data['#'] = '<span style="font-size: 12px ; text-align: center;">'.$counter++.'</span>';
$nested_data['name'] = '<p style="text-align: center;">'.$post->name.'</p>';
$nested_data['address'] = '<p style="text-align: center;">'.$post->address.'</p>';
$nested_data['contact'] = '<p style="text-align: center;">'.$post->contact.'</p>';
$nested_data['department'] = '<p style="text-align: center;">'.$department->name.'</p>';
$nested_data['status'] = '<p style="text-align: center;">'.$status.'</p>';
$nested_data['actions'] = '';
$data[] = $nested_data;
}
}
$json_data=array(
"draw" => intval($request->input('draw')),
"recordsTotal" => intval($total_data),
"recordsFiltered" => intval($total_filtered),
"data" => $data
);
return response()->json($json_data);
}
In the second line of your viewModal() function, you are placing a return false; statement. "The return statement ends function execution and specifies a value to be returned to the function caller." From Mozilla docs. That's why the API call is never executing.

Initialization datatable via Ajax - No data displayed

I have a datatable that I would like to initialize with an Ajax call http://url/api/v1/shocks
table.blade.php
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-striped table-md" id="table-raw-shocks" width="100%" cellspacing="0">
<thead>
<tr>
<th>Record Id</th>
<th>Count</th>
<th>Date</th>
<th>Amplitude 1 (G)</th>
<th>Amplitude 2 (G)</th>
<th>Time 1 (s)</th>
<th>Time 2 (s)</th>
<th>Freq 1 (Hz)</th>
<th>Freq 2 (Hz)</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Record Id</th>
<th>Count</th>
<th>Date</th>
<th>Amplitude 1 (G)</th>
<th>Amplitude 2 (G)</th>
<th>Time 1 (s)</th>
<th>Time 2 (s)</th>
<th>Freq 1 (Hz)</th>
<th>Freq 2 (Hz)</th>
</tr>
</tfoot>
</table>
</div>
</div>
Javascript part
$(document).ready(function () {
initShocksActivityTable();
});
function initShocksActivityTable() {
var url = '{{ route("api:v1:shocks.index") }}'; //http://url/api/v1/shocks
var table = $('#table-raw-shocks-all').DataTable({
responsive: true,
responsive: {
details: {
type: "column",
target: "tr"
}
},
orderCellsTop: true,
fixedHeader: true,
dom: "Bfrtip",
buttons: ["copy", "csv", "excel", "pdf", "print"],
columnDefs: [{
sortable: true
}],
"ajax": url,
"columns": [{
"data": "attributes.record_id"
},
{
"data": "attributes.count"
},
{
"data": "attributes.date_time"
},
{
"data": "attributes.amplitude_1"
},
{
"data": "attributes.amplitude_2"
},
{
"data": "attributes.time_1"
},
{
"data": "attributes.time_2"
},
{
"data": "attributes.freq_1"
},
{
"data": "attributes.freq_2"
},
],
lengthMenu: [
[10, 25, 50, -1],
[10, 25, 50, "All"]
],
iDisplayLength: 10,
order: [
[2, "desc"]
]
});
}
My data looks like this :
Attributes contains all the necessary data that I would like to add on my datatable.
When I do that, I have no data displayed. I suspect that it is because, my data is an array ( [0], 1...)
I tried to add this piece of code (https://datatables.net/reference/option/ajax.dataSrc)
"dataSrc": "data.attributes"
But it still does not work.
I'm sure, it's something that I missed but I have some difficulties to find what is the problem to fetch correctly the data.
Could you please help me on that ? Thank

How to show nested array data in vuejs component

I'm running the following query:
$users=User::with('roles.permissions')->get()->unique();
this query returns result set:
Array = [
{
created_at: "2019-01-11 09:27:02",
deleted_at: null,
email: "admin#example.com",
email_verified_at: null,
id: 1,
name: "ADMIN",
roles: [
{id: 1, name: "Admin", slug: "Admin", description: "This is Super-Admin Role", created_at: "2019-01-11 09:27:02",
permissions: [
{id:1, name:"Create,slug:"Create"},
{id:1, name:"Read",slug:"Read"},
{id:1, name:"Delete",slug:"Delete"},
],
},
],
},
]
returns user details with roles I want to show this result set in my Vue Component table.
this my vue component read method
read:function(){
axios.get('/userlist')
.then(response=>{
console.log(response.data);
})
}
This is my table
<table class="table table-bordered">
<thead>
<th>no.</th>
<th>Name</th>
<th>E-mail</th>
<th>Roles</th>
<th>Permissions</th>
<th>Action</th>
</thead>
<tbody>
<tr v-for="(user,key) in users">
<td>{{++key}}</td>
</tr>
</tbody>
</table>
How to show user,roles and permissions separately in html table.
You should store your API result in your component data. But you need to prepare your component data to receive your users.
data() {
return {
users: []
}
}
Now, you should make your function update this brand new data.
read:function(){
axios.get('/userlist')
.then(response=>{
this.users = response.data;
})
}
Now, I assume that you want to display user's roles as a concatenated string. Then, you need a function to do this.
methods: {
getRoles: function(roles) {
let rolesString = ''
roles.forEach((role, index) => {
if (index != 0)
rolesString += ', '
rolesString = rolesString + role.name
})
return rolesString
},
getPermissionsFromRoles: function(roles) {
let permissionsList = []
roles.permissions.forEach((permission) => {
if (permissionsList.indexOf(permission.name) != -1) {
permissionsList.push(permission.name)
}
})
let permissionsString = ''
if (permissionsList.length > 0) {
permissionsList.forEach((permission, index) => {
if (index != 0)
permissionsString += ', '
permissionsString += permission
})
}
return permissionsString
}
}
Then, you can use this function in your template to handle your user roles.
<table class="table table-bordered">
<thead>
<th>no.</th>
<th>Name</th>
<th>E-mail</th>
<th>Roles</th>
<th>Permissions</th>
</thead>
<tbody>
<tr v-for="(user,key) in users">
<td>{{key}}</td>
<td>{{user.name}}</td>
<td>{{user.email}}</td>
<td>{{getRoles(user.roles)}}</td>
<td>{{getPermissionsFromRoles(user.roles)}}</td>
</tr>
</tbody>
</table>
rendering in the template will look like:
<td v-for="role in roles">{{role}}</td>
you will also need to have roles in your data:
data() {
return {
roles: []
}
}
and finally make your function update the data
function(){
.then(response=>{
this.roles = response.data
})
}

How to use vuetify's custom sort?

I'd like to use custom-sort in my data table. My goal is to sort the table DESC as opposed to the default ASC. But I don't know-how.
This is the start of my data table component:
<v-data-table
:headers="headers"
:items="acts"
hide-actions
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td>{{ props.item.id }}</td>
<td>{{ props.item.name }}</td>
<td class="text-xs-center">{{ props.item.provider.id }}</td>
<td class="text-xs-center">{{ props.item.category.name }}</td>
<td class="text-xs-center">{{ props.item.budget }}</td>
<td class="text-xs-center">{{ props.item.location.name }}</td>
<td class="text-xs-center">{{ props.item.deets }}</td>
<td class="text-xs-center">{{ props.item.keeping_it_100 }}</td>
<td class="text-xs-center"><img width="50" height="50" :src="props.item.inspiration.inspiration"></td>
<td class="justify-center layout px-0">....
And this is the script I'm using:
<script>
export default {
data () {
return {
dialog: false,
customerSort: {
isDescending: true,// I tried this? as the kabab format throws an error
},
headers: [
{ text: 'ID', value: 'id'},
{ text: 'Name', value: 'name' },
{ text: 'Provider', value: 'provider' },
{ text: 'Category', value: 'category' },
{ text: 'Budget', value: 'budget' },
{ text: 'Country', value: 'location', sortable: true },
{ text: 'Keeping it 100%', value: 'keeping_it_100', sortable: false },
{ text: 'deets', value: 'deets', sortable: false },
{ text: 'inspiration', value: 'inspiration', sortable: false },
{ text: 'Cover', value: 'cover', sortable: false },
{ text: 'Actions', value: 'actions', sortable: false }
],
According to docs it is a function prop. But I haven't found an example on how to pass it.
This is a screenshot of the function...
You can use a function like this-
customSort(items, index, isDesc) {
items.sort((a, b) => {
if (index === "date") {
if (!isDesc) {
return compare(a.date, b.date);
} else {
return compare(b.date, a.date);
}
}
});
return items;
}
Where the compare is a function which compares a.date and b.date and returns 1 or -1
isDesc is a variable passed by the table which tells in what order does the user want to sort it. If you want to sort in desc, just use !isDesc in the if-else condition
To use this in your template just use
<v-data-table
:headers="headers"
:items="Data"
:custom-sort="customSort"
>
<template slot="items" slot-scope="props">
<td class="font-weight-black">{{ props.item.date }}</td>
<td class="text-xs-right">{{ props.item.time }}</td>
<td class="text-xs-right">{{ props.item.name }}</td>
</template>
</v-data-table>
To make sure your other fields still work with the normal sort use
customSort(items, index, isDesc) {
items.sort((a, b) => {
if (index === "date") {
if (!isDesc) {
return dateHelp.compare(a.date, b.date);
} else {
return dateHelp.compare(b.date, a.date);
}
} else {
if (!isDesc) {
return a[index] < b[index] ? -1 : 1;
} else {
return b[index] < a[index] ? -1 : 1;
}
}
});
return items;
}
Although it's an old question ...
For special sorting of only one column, you could use the property sort in the headers array.
See also https://vuetifyjs.com/en/api/v-data-table/#headers
Like so:
// in data ...
headers: [
...
{
text: "Date",
sortable: true,
value: "date",
sort: (a, b) => a.time_stamp - b.time_stamp
},
...
]
use it like
<v-data-table
:headers="headers"
...
>
Based on this answer code about custom-filter, I tried using custom-sort.
Please refer to this answer if you apply it to your code.
By the following code, I have confirmed sorting when I click 'Calories' header.
My CodePen
new Vue({
el: '#app',
data() {
return {
food: [
{ name: 'Bakchoi', type: 'vegetable', calories: 100 },
{ name: 'Pork', type: 'meat', calories: 200 },
{ name: 'Chicken Thigh', type: 'meat', calories: 300 },
{ name: 'Watermelon', type: 'fruit', calories: 10 },
],
headers: [
{ text: 'Name', align: 'left', value: 'name' },
{ text: 'Food Type', align: 'left', value: 'type' },
{ text: 'Calories', align: 'left', value: 'calories' },
],
search: '',
};
},
methods: {
customSort(items, index, isDescending) {
// The following is informations as far as I researched.
// items: 'food' items
// index: Enabled sort headers value. (black arrow status).
// isDescending: Whether enabled sort headers is desc
items.sort((a, b) => {
if (index === 'calories') {
if (isDescending) {
return b.calories - a.calories;
} else {
return a.calories - b.calories;
}
}
});
return items;
}
}
})
<script src="https://unpkg.com/vue#2.4.2/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#0.15.2/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#0.15.2/dist/vuetify.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">
<div id="app">
<v-app>
<v-select
label="Food Type"
:items="['vegetable', 'meat', 'fruit']"
v-model="search"
></v-select>
<v-data-table
:headers="headers"
:items="food"
:search="search"
:custom-sort="customSort"
hide-actions
>
<template slot="items" scope="{ item }">
<td>{{ item.name }}</td>
<td>{{ item.type }}</td>
<td>{{ item.calories }}</td>
</template>
</v-data-table>
</v-app>
</div>
NOTE: the following answer is for Vuetify 1.5.x
A little late to the party here, if all you want to do is sort descending by a single field, then custom-sort it not what you want to use, you're better off using the :pagination.sync prop
Custom sort is used when you want to change the behaviour of the comparison function (e.g sorting based off the reverse or lowercase version of a string, or proper sorting of date strings in the format 'DD-MM-YYYY').
If you want to use the default descending functionality, use the :pagination.sync prop, like so:
<v-data-table
:headers="headers"
:items="acts"
:pagination.sync="pagination"
>
<template v-slot:items="props">...</template>
</v-data-table>
In your script, set pagination:
data () {
return {
pagination: {
sortBy: 'id', // The field that you're sorting by
descending: true
}
}
}
This specifies that you want the table to be initially sorted by descending id - id can be changed to any field name in the dataset.
It's worth noting that this only specifies the default behaviour, and if you have sorting enabled for your other headers, users can still sort the table by any field.
To Build on the response provided by bhaskar
I had to edit the last code sample to the following in order to work on vuetify 2.x. The code sorts the date columns by their epoch time which is stored under the time_stamp key. The code also allows the default sorting of numbers and strings (strings are sorted alphabetically)
customSort(items, index, isDesc) {
items.sort((a, b) => {
if (index[0] == "date") {
if (!isDesc[0]) {
return a.time_stamp - b.time_stamp;
} else {
return b.time_stamp - a.time_stamp;
}
} else if (!(isNaN(a[index[0]]))) {
if (!isDesc[0]) {
return (a[index[0]] - b[index[0]]);
} else {
return (b[index[0]] - a[index[0]]);
}
} else {
if (!isDesc[0]) {
return (a[index[0]] < b[index[0]]) ? -1 : 1;
} else {
return (b[index[0]] < a[index[0]]) ? -1 : 1;
}
}
});
return items;
}
In vuetify 2 just use sortBy="date" and update: sort-desc
<v-data-table
:headers="headers"
:items="acts"
:pagination.sync="pagination"
sortBy="date"
update: sort-desc
>

Durandal and jqGrid

There is already an example of jqxGrid that is labeled "jqGrid integration with existing Durandal solution". However, I don't have the option of using jqxGrid.
Does any one have an example of using jqGrid with durandal. This is what I'm trying now and it is not working.
Unable to parse bindings.
Bindings value: attr: { href: 'animals/' + id, title: name }, text: id
Message: id is not defined;
viewmodel.js
///
define(['durandal/app', 'jqgrid', 'kojqgrid'], function (app) {
var initialData = [
{ id: 1, name: "Well-Travelled Kitten", sales: 352, price: 75.95 },
{ id: 2, name: "Speedy Coyote", sales: 89, price: 190.00 },
{ id: 3, name: "Furious Lizard", sales: 152, price: 25.00 },
{ id: 4, name: "Indifferent Monkey", sales: 1, price: 99.95 },
{ id: 5, name: "Brooding Dragon", sales: 0, price: 6350 },
{ id: 6, name: "Ingenious Tadpole", sales: 39450, price: 0.35 },
{ id: 7, name: "Optimistic Snail", sales: 420, price: 1.50 }
];
var ctor = function () {
this.animals = ko.observableArray([]);
this.disabled = ko.observable(false);
this.activate = function () {
this.animals(initialData);
return true;
}
};
//Note: This module exports a function. That means that you, the developer, can create multiple instances.
//This pattern is also recognized by Durandal so that it can create instances on demand.
return ctor;
});
View
-------------------------------------------------------------------
<h3>Customers</h3>
<table id="animals" data-bind="grid: { data: animals }" >
<caption>Amazing Animals</caption>
<thead>
<tr>
<th data-field="actions" style="width:27px;"></th>
<th data-field="name" width="150px">Item Name</th>
<th data-field="sales">Sales Count</th>
<th data-field="price">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td data-field="actions">
<a class="grid-edit" data-bind="attr: { href: 'animals/' + id, title: name }, text: id"></a>
</td>
</tr>
</tbody>
</table>
Any help would be greatly appreciated.
The reason you are getting id is undefined is because the ctor function does not expose id or name attribute but the animals observableArray. In your view you need to loop over the animals obserbavbleArray to get access to id and name attribute for each animal. Try the following code:
<tbody data-bind='foreach:animals'>
<tr>
<td data-field="actions">
<a class="grid-edit" data-bind="attr: { href: 'animals/' + id, title: name }, text: id"></a>
</td>
</tr>
</tbody>
You need to put your activate handler on the prototype:
ctor.prototype.activate = function () {...}
Durandal likely cannot find your activate handler and, therefore, never initializes the data.
Also, I can only assume that the jqGrid binding is looking at the table definition and harvesting from the DOM what it needs to build a proper binding. The reason I say that is that, strictly speaking, #nimrig is right: there needs to be a foreach somewhere. It must be that the jqGrid is building that foreach.

Resources