3

I have put together a simple CRUD application and have most of it working but cannot seem to figure out how to sort the table columns. I have a working demo here: http://codepen.io/figaro/pen/MJMqYR

var products = [{
    id: 1,
    name: 'Angular',
    description: 'Superheroic JavaScript MVW Framework.',
    price: 900
  },
  {
    id: 2,
    name: 'Ember',
    description: 'A framework for creating ambitious web applications.',
    price: 600
  },
  {
    id: 3,
    name: 'React',
    description: 'A JavaScript Library for building user interfaces.',
    price: 500
  }
];

function findProduct(productId) {
  return products[findProductKey(productId)];
};

function findProductKey(productId) {
  for (var key = 0; key < products.length; key++) {
    if (products[key].id == productId) {
      return key;
    }
  }
};

var sortable = Vue.extend({
  data: {
    sortKey: 'name',

    reverse: false,

  }
})

var List = Vue.extend({
  template: '#product-list',
  data: function() {
    return {
      products: products,
      searchKey: ''
    };
  }
});

var Product = Vue.extend({
  template: '#product',
  data: function() {
    return {
      product: findProduct(this.$route.params.product_id)
    };
  }
});

var ProductEdit = Vue.extend({
  template: '#product-edit',
  data: function() {
    return {
      product: findProduct(this.$route.params.product_id)
    };
  },
  methods: {
    updateProduct: function() {
      var product = this.$get('product');
      products[findProductKey(product.id)] = {
        id: product.id,
        name: product.name,
        description: product.description,
        price: product.price
      };
      router.go('/');
    }
  }
});

var ProductDelete = Vue.extend({
  template: '#product-delete',
  data: function() {
    return {
      product: findProduct(this.$route.params.product_id)
    };
  },
  methods: {
    deleteProduct: function() {
      products.splice(findProductKey(this.$route.params.product_id), 1);
      router.go('/');
    }
  }
});

var AddProduct = Vue.extend({
  template: '#add-product',
  data: function() {
    return {
      product: {
        name: '',
        description: '',
        price: ''
      }
    }
  },
  methods: {
    createProduct: function() {
      var product = this.$get('product');
      products.push({
        id: Math.random().toString().split('.')[1],
        name: product.name,
        description: product.description,
        price: product.price
      });
      router.go('/');
    }
  }
});

var router = new VueRouter();
router.map({
    '/': {
      component: List
    },
    '/product/:product_id': {
      component: Product,
      name: 'product'
    },
    '/add-product': {
      component: AddProduct
    },
    '/product/:product_id/edit': {
      component: ProductEdit,
      name: 'product-edit'
    },
    '/product/:product_id/delete': {
      component: ProductDelete,
      name: 'product-delete'
    }
  })
  .start(Vue.extend({}), '#app');
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <title>School Application</title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>

  <div class="container">

    <header class="page-header">
      <div class="branding">

        <h2>School Application</h2>
      </div>
    </header>
    <main id="app">
      <router-view></router-view>
    </main>
  </div>


  <template id="product-list">
      <div class="actions">
        <a class="btn btn-default" v-link="{path: '/add-product'}">
          <span class="glyphicon glyphicon-plus"></span>
          Add new entry
        </a>
      </div>
      <div class="filters row">
        <div class="form-group col-sm-3">

          <input v-model="searchKey" class="form-control"placeholder="Search..." id="search-element" requred/>
        </div>
      </div>
      <table class="table highlight bordered">
        <thead>
        <tr>
          <th>Name</th>
          <th>Description</th>
          <th>Price</th>
          <th class="col-sm-2">Actions</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="product in products | filterBy searchKey in 'name'">
          <td>
            <a v-link="{name: 'product', params: {product_id: product.id}}">{{ product.name }}</a>
          </td>
          <td>{{ product.description }}</td>
          <td>
            {{ product.price }}
            <span class="glyphicon glyphicon-euro" aria-hidden="true"></span>
          </td>
          <td>
            <a class="btn btn-warning btn-xs" v-link="{name: 'product-edit', params: {product_id: product.id}}">Edit</a>
            <a class="btn btn-danger btn-xs" v-link="{name: 'product-delete', params: {product_id: product.id}}">Delete</a>
          </td>
        </tr>
        </tbody>
      </table>
    </template>

  <template id="add-product">
      <h3>Add new product</h3>
      <form v-on:submit="createProduct">
        <div class="form-group">
          <label for="add-name">Name</label>
          <input class="form-control" id="add-name" v-model="product.name" required/>
        </div>
        <div class="form-group">
          <label for="add-description">Description</label>
          <textarea class="form-control" id="add-description" rows="10" v-model="product.description"></textarea>
        </div>
        <div class="form-group">
          <label for="add-price">Price, <span class="glyphicon glyphicon-euro"></span></label>
          <input type="number" class="form-control" id="add-price" v-model="product.price"/>
        </div>
        <button type="submit" class="btn btn-primary">Create</button>
        <a v-link="'/'" class="btn btn-default btn-danger">Cancel</a>
      </form>
    </template>

  <template id="product">
      <h2>{{ product.name }}</h2>
      <b>Description: </b>
      <div>{{ product.description }}</div>
      <b>Price:</b>
      <div>{{ product.price }}<span class="glyphicon glyphicon-euro"></span></div>
      <br/>
      <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>
      <a v-link="'/'">Back to product list</a>
    </template>

  <template id="product-edit">
      <h2>Edit product</h2>
      <form v-on:submit="updateProduct">
        <div class="form-group">
          <label for="edit-name">Name</label>
          <input class="form-control" id="edit-name" v-model="product.name" required/>
        </div>
        <div class="form-group">

        </div><div class="form-group">
          <label for="edit-description">Description</label>
          <textarea class="form-control" id="edit-description" rows="3" v-model="product.description"></textarea>
        </div>
        <div class="form-group">
          <label for="edit-price">Price, <span class="glyphicon glyphicon-euro"></span></label>
          <input type="number" class="form-control" id="edit-price" v-model="product.price"/>
        </div>
        <button type="submit" class="btn btn-primary">Save</button>
        <a v-link="'/'" class="btn btn-danger">Cancel</a>
      </form>
    </template>

  <template id="product-delete">
      <h2>Delete product {{ product.name }}</h2>
      <form v-on:submit="deleteProduct">
        <p>The action cannot be undone.</p>
        <button type="submit" class="btn btn-danger">Delete</button>
        <a v-link="'/'" class="btn btn-default">Cancel</a>
      </form>
    </template>

</body>

</html>

I do apologize if this is simple, I just don't understand what I am missing.

2
  • 1
    I don't see where you are using sortable?(´・_・`) Commented Feb 21, 2017 at 10:44
  • I dont know how to make sortable do what I named it. Commented Feb 21, 2017 at 14:21

1 Answer 1

8

You should create a computed property e.g. sortedData and you should do simple Javascript sorting :

computed: {
  sortedData: function() {
     return this.data.sort(function(a, b) {
        return a.name > b.name;
     });
  }
}

Then you should use the computed property in your list.


Sign up to request clarification or add additional context in comments.

4 Comments

and how would that be implemented?
I've written how it's done. If you want more concrete implementation create a jsfiddle and I will show you. The products and the methods should be part of the Vue instance and you should use sortedData in the v-for.
I have a case where my data (array of objects) is switched up/down when some object values change ... but wanna keep the rows fixed!
Not sure if sort() with a comparison inside is the right way. I had to do something like a.id - b.id to get it working rather than a.id > b.id

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.