Vue.js Data binding issue - javascript

I am trying to bind data in my userDetails array through post request but i did not get the data , i had tried all the possible solution given in stackoverflow and also in vue.js docs but nothing helps me here is my code.
ND.user_list = new Vue({
el: '#user_list',
data: {
userDetails: []
},
mounted: function () {
$.post(ND.routes['users.get'], [], function(data) {
//console,log(data);
this.$set(this, 'userDetails', data);
//this.usersDetails = data;
}.bind(this), 'json');
//onsole.log(this.userDetailsdata);
}
});
i am getting data in console log in mounted function but not getting in userDetails array declare in data. here is my view code
<div class="ui grid container" id="user_list">
<table class="ui celled padded table">
<thead>
<tr>
<th colspan="6">Top Users</th>
</tr>
</thead>
<thead>
<tr>
<th class="ui center aligned">#</th>
<th class="ui center aligned">Name </th>
<th class="ui center aligned">Email </th>
<th class="ui center aligned">User Type</th>
<th class="ui center aligned">Action </th>
</tr>
</thead>
<tbody>
{% verbatim %}
<tr v-for="user in userDetails">
<td>1</td>
<td class="single line">{{ user.email }}</td>
<td class="ui center aligned "></td>
<td class="ui center aligned "></td>
<td class="ui center aligned ">
<select class="ui dropdown">
<option value=" ">Action </option>
<option value="1">Edit</option>
<option value="0">Delete</option>
</select>
</td>
</tr>
{% endverbatim %}
</tbody>
</table>
</div>
Thanks in advance.

The this in the callback fo $.post() does not refer to the VueJS instance. This means that this.userDetails actually will return undefined within the callback. What you can do is to create a proxy for the VueJS instance as such:
ND.user_list = new Vue({
el: '#user_list',
data: {
userDetails: []
},
mounted: function () {
// Proxy `this`
var that = this;
$.post(ND.routes['users.get'], [], function(data) {
// `that` will refer to VueJS instance
that.userDetails = data;
}, 'json');
}
});

You are using this.$set wrong: it should only be used when you got an object in the data object and want to add properties to that object that wasn't there before, or if you want to change indexes of the array. Then first argument should not be the vue object, but the data object (i.e. the object or array in the data object). See documentation here: https://v2.vuejs.org/v2/guide/reactivity.html or https://v2.vuejs.org/v2/api/#Vue-set.
Instead of: this.$set(this, 'userDetails', data); you should just do this.userDetails = data;. Have you tried this? Also, if you change elements in the array, then you should use Vue.set or splice, but read the documentation carefully before you use it.

Related

Get value from array data in Vue

I'm kinda new to Vue and i'm struggling to get one value from an array. I'm making an axios get request where I return an array of users containing the values (name, display_name, role, and few others fields). I'm able to get all these values and mount my table with the component below:
<template>
<div class="container">
<table class="mt-3 table roboto table-stripped table-hover table-sm">
<thead class="thead-light">
<th>Name</th>
<th>Username</th>
<th>Profile</th>
<th class="text-center">Is manager</th>
</thead>
<tbody v-for="user in users">
<td v-text="user.name"></td>
<td v-text="user.username"></td>
<td v-text="user.display_name"></td>
<td class="text-center">
<button
class="letter-shadow btn-sm font-500 grey-darkest roboto letter-spacing"
:class="showRole">Activate
</button>
</td>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
return {
users: [],
}
},
computed: {
showRole() {
// wanted to diff button colors here
}
},
mounted() {
axios.get('/api/users').then(response => this.users = response.data);
},
}
</script>
So I wanted to modify that class showRole depending on the value of user.display_name, if the user.display_name is equal to "Manager" e.g. I would show a btn-danger. I just don't know how can I get this value to compare, if I try to use this.user.display_name on showRole method I get nothing (undefined). Thanks for any help.
I think you should use a method instead, as you can't pass parameters to computed properties.
Use this
...
methods : {
showRole(user){
//code that returns the button class
}
}
...
<button :class="showRole(user)">Activate

How can I retrieve data from an array which is inside another array and display it in the table?

Using Vue.js , I am able to retrieve and display id,description and location, but why in the tasks column I only have [object Object] in all the rows ?!
(tasks is an array inside jobs array)
<template>
<div>
...
<table class="table table-hover">
<thead>
<tr>
<th v-for="column in columns">
...
</th>
</tr>
</thead>
<tbody>
<tr v-for="work in jobs">
<td>{{work["id"]}}</td>
<td>{{work["description"]}}</td>
<td>{{work["location"]}}</td>
<td v-for="tasks in jobs" >{{work["tasks"]}}</td>
</tr>
</tbody>
</table>
<script>
export default{
data : function() {
return{
columns: ['id', 'description', 'location', 'tasks'],
jobs: '',
update: this.getData()
}
},
methods: {
//to get data from the backend API
getData() {
this.$http
.get('http://localhost:3001/api', (data) => {
this.jobs = data["jobs"]
})
}
}
</script>
You are iterating over jobs and not each task inside the job's tasks
You should do something like -
<tr v-for="work in jobs">
<td>{{work["id"]}}</td>
<td>{{work["description"]}}</td>
<td>{{work["location"]}}</td>
<td v-for="task in work.tasks" >{{task["id"]}} -
{{task["description"]}} - {{task["location"]}}</td>
</tr>
Or however you want to display there. But the idea should be to iterate on the tasks array inside each work object
You'll need to explicitly extract the fields that you want to show from tasks. Also, the syntax for the nested v-for would be something like task in work.tasks, so that your task points to each task inside of your tasks array for each work:
<tr v-for="work in jobs">
<td>{{work["id"]}}</td>
<td>{{work["description"]}}</td>
<td>{{work["location"]}}</td>
<td v-for="task in work.tasks">
{{task["id"]}} <br>
{{task["description"]}} <br>
{{task["location"]}}
</td>
</tr>

Edit object of an array using Vue.JS

I am developing my first app using Vuejs + Laravel and I am facing a problem that I couldn't solve until now!
I have an array of object and I need to edit a single of then without delete and add a new one! I have made a JS Bin to show what I need!
JS Bin
When you click in EDIT and start to typing your new value the original value edits as well but I need to change the original value only after the user hit the save button!
Anybody can help me?
PS: I will update my database and then show the new value on the table!
Is there anyway to duplicate my record as I do on the edit function without sync then?
JS
new Vue({
el: 'body',
data: {
cache: {},
record: {},
list: [
{ name: 'Google', id: 1 },
{ name: 'Facebook', id: 2 },
],
},
methods: {
doEdit: function (record) {
this.cache = record;
},
edit: function (record) {
this.record = _.cloneDeep(record);
this.cache = record;
}
}
});
HTML
<div class="container">
<form class="form-horizontal" #submit.prevent="doEdit(record)">
<div class="row">
<div class="col-md-12">
<label>Name</label>
<input type="text" class="form-control" v-el:record-name v-model="record.name">
</div>
<div class="col-xs-12" style="margin-top:15px">
<button type="submit" class="col-xs-12 btn btn-success">Save</button>
</div>
</div>
</form>
<hr>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="r in list">
<td class="text-center" style="width:90px"> {{ r.id }} </td>
<td> {{ r.name }} </td>
<td class="text-center" style="width:90px">
<span class="btn btn-warning btn-xs" #click="edit(r)"><i class="fa-fw fa fa-pencil"></i></span>
</td>
</tr>
</tbody>
</table>
</div>
You can replace the old object with the cloned-updated one.
doEdit: function (record) {
var index = _.indexOf(this.list, this.cache);
this.list.splice(index, 1, record);
}
https://jsbin.com/ruroqu/3/edit?html,js,output
If you want to save the value only after user submitted, you should not bind the record directly such as v-model="record.name".
And we can use Vue.set to change attributes of the original record.
Let's try: JS Bin

Vue.js $remove not removing element after deleted from database

I am using Laravel and trying to learn Vue.js. I have a delete request that is working properly and deleting the object from the database. The problem is that it is not being removed from the DOM after the successful deletion. I am using the $remove method and passing it the full object, so I know I'm missing something.
As a side note, I have a main.js as an entry point with a PersonTable.vue as a component. The PersonTable.vue holds the template and script for that template.
Here is my Laravel view:
<div id="app">
<person-table list="{{ $persons }}">
</person-table>
</div>
And here is my `PersonTable.vue:
<template id="persons-template">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h1>Persons List</h1>
<table class="table table-hover table-striped">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Email</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
<tr v-for="person in list">
<td>{{person.first_name }}</td>
<td>{{person.last_name }}</td>
<td>{{person.email }}</td>
<td>{{person.gender }}</td>
<td><span #click="deletePerson(person)">X</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
template: '#persons-template',
props: ['list'],
methods: {
deletePerson: function(person) {
this.$http.delete('/person/' + person.id).then(
function(response) {
this.persons.$remove(person);
}
);
}
},
created: function() {
this.persons = JSON.parse(this.list);
}
};
</script>
And my main.js entry point:
var Vue = require('vue');
Vue.use(require('vue-resource'));
var Token = document.querySelector('meta[name="_token"]').getAttribute('content');
Vue.http.headers.common['X-CSRF-TOKEN'] = Token;
import PersonTable from './components/PersonTable.vue';
new Vue({
el: '#app',
components: { PersonTable },
})
I think you need to bind this to the response function:
function(response) {
this.persons.$remove(person);
}.bind(this)
That way when you do this.persons you are still referring to the Vue component
edit: could try -
props:['personJson'],
data:function(){
return {
persons:[]
}
},
ready:function(){
this.persons = JSON.parse(this.personJson)
}
Thinking maybe since persons is a string initially, Vue isn't binding the reactive capabilities properly?
I think that you need to use the this.$set in your created method, if you don't, I am afraid that Vue would lose reactivity.
In your created method, could you try the following:
export default {
template: '#persons-template',
props: ['persons'],
methods: {
deletePerson: function(person) {
var self = this;
this.$http.delete('/person/' + person).then(
function(response) {
self.persons.$remove(person);
}
);
}
},
created: function() {
this.$set('persons',JSON.parse(this.persons));
}
};
Finally figured it out. I needed to pass the JSON data to my data property of the component. Here is the code.
In the blade file:
<div id="app">
<person-table list="{{ $persons }}">
</person-table>
</div>
In my PersonTable.vue file:
<template id="persons-template">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h1>Persons List</h1>
<table class="table table-hover table-striped">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Email</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
// Notice how I am using persons here instead of list
<tr v-for="person in persons">
<td>{{person.first_name }}</td>
<td>{{person.last_name }}</td>
<td>{{person.email }}</td>
<td>{{person.gender }}</td>
<td><span class="delete person" #click="deletePerson(person)"><i class="fa fa-close"></i></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
template: '#persons-template',
props: ['list'],
data: function() {
return {
persons: []
}
},
methods: {
deletePerson: function(person) {
this.$http.delete('/person/' + person.id).then(
function(response) {
this.persons.$remove(person);
}
);
},
},
created: function() {
// Pushing the data to the data property so it's reactive
this.persons = JSON.parse(this.list);
},
};
</script>
Thanks to everyone for their contributions. I almost ditched Vue because of how long it has taken to fix this error.

Get data-bind value of button in html table

How get data-bind value in ViewsModel from Button in html table when click ?
Please help me?
Views:
<table border="1">
<thead>
<tr>
<th>
Id
</th>
<th>
Naziv
</th>
</tr>
</thead>
<tbody data-bind="foreach: customers">
<tr>
<td data-bind="text: Id_dobavljaca">
</td>
<td data-bind="text: NazivDobavljaca">
</td>
<td>
<button data-bind="click: edit, value: Id_dobavljaca">
Edit</button>
<button >
Test</button>
</td>
</tr>
</tbody>
</table>
ViewModel:
define(function (require) {
var app = require('durandal/app'), system = require('durandal/system'),
ko = require('knockout');
return {
customers: ko.observableArray([]),
activate: prikazi
}
});
function prikazi() {
var system = require('durandal/system');
var that = this;
system.log('krenu po podatke');
$.ajax({
type: 'GET',
url: '/Durandal/VratiDobavljace',
dataType: "json",
success: function (data) {
that.customers(data);
},
error: function (jq, st, error) {
alert(error);
}
});
system.log('doneo podatke');
edit = function edit1(Id_dobavljaca) {
var system = require('durandal/system');
alert(Id_dobavljaca);
var router = require('plugins/router');
router.navigate('treci/' + 123456);
};
return that.customers
}
I want to pass value ( Id_dobavljaca )in ViewsModels when click button in html table..
Thanks alot!
Martin
In DurandalJS, the object that you return from your requirejs module that is your view model is the object bound to the view. The activate function will be called when DurandalJS composes your view and view model, you can read more here.
In your current implementation the observableArray customers is a property on your view model and can be bound to your view, which is great and I assume working.
However, from looking at your current implementation you have not exposed the edit function on your view model which means it cannot be bound to the UI and used.
I have refactored your view model:
define(function(require) {
var app = require('durandal/app'),
system = require('durandal/system'),
router = require('plugins/router'),
ko = require('knockout');
var customers = ko.observableArray([]);
return {
customers: customers,
edit: function(context) {
alert(context.Id_dobavljaca);
router.navigate('treci/' + context.Id_dobavljaca);
},
activate: function() {
system.log('krenu po podatke');
return $.ajax({
type: 'GET',
url: '/Durandal/VratiDobavljace',
dataType: "json"
})
.done(function(data) { customers(data); })
.fail(function(jq, st, error) { alert(error); })
.always(function() { system.log('doneo podatke'); });
}
}
});
This refactoring exposes the customers observableArray property and the edit function. The activate function also loads your data and returns the promise back to the DurandalJS composition life cycle.
Now, you will notice that the edit function takes an argument called context, this is a knockoutjs thing. When a function is bound to the click binding the first argument passed to the function is the binding context, you can read more here.
Using this refactored view model, in your markup you want to bind your edit button to the edit function on the $root context, which is your view model.
<td>
<button data-bind="click: $root.edit">Edit</button>
<button>Test</button>
</td>
Hopefully, the snippet below can demonstrate this explanation.
var example1 = {
customers: ko.observableArray([{
Id_dobavljaca: 123,
NazivDobavljaca: 'Martin',
edit: function(context) {
alert('Id_dobavljaca: ' + this.Id_dobavljaca);
alert('Id_dobavljaca: ' + context.Id_dobavljaca);
}
}, {
Id_dobavljaca: 321,
NazivDobavljaca: 'Anish',
edit: function(context) {
alert('Id_dobavljaca: ' + this.Id_dobavljaca);
alert('Id_dobavljaca: ' + context.Id_dobavljaca);
}
}, ])
}
ko.applyBindings(example1, $('#example1')[0]);
var example2 = {
customers: ko.observableArray([{
Id_dobavljaca: 123,
NazivDobavljaca: 'Martin'
}, {
Id_dobavljaca: 321,
NazivDobavljaca: 'Anish'
}, ]),
edit: function(context) {
alert('Id_dobavljaca: ' + context.Id_dobavljaca);
}
}
ko.applyBindings(example2, $('#example2')[0]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<p>Edit function is a property on each customer object<p>
<table id="example1" border="1">
<thead>
<tr>
<th>
Id
</th>
<th>
Naziv
</th>
</tr>
</thead>
<tbody data-bind="foreach: customers">
<tr>
<td data-bind="text: Id_dobavljaca">
</td>
<td data-bind="text: NazivDobavljaca">
</td>
<td>
<button data-bind="click: edit">
Edit</button>
<button>
Test</button>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<br>
<p>Edit function is a property on the view model<p>
<table id="example2" border="1">
<thead>
<tr>
<th>
Id
</th>
<th>
Naziv
</th>
</tr>
</thead>
<tbody data-bind="foreach: customers">
<tr>
<td data-bind="text: Id_dobavljaca">
</td>
<td data-bind="text: NazivDobavljaca">
</td>
<td>
<button data-bind="click: $root.edit">
Edit</button>
<button>
Test</button>
</td>
</tr>
</tbody>
</table>
I hope this helps.

Categories

Resources