push value in select option in vue - laravel-5

I m new to Vue and don't know how to solve this kind of problem I search a lot but haven't find any solution related to my problem
here is my code
<tbody >
<tr v-for="(col, index) in cols">
<td>12345</td>
<td><select class="form-control" v-model="col.select1" >
<option>Select Shop</option>
<option v-for="option1 in options1" :value="option1.name">
{{option1.name}}</option>
</select>
</td>
</tbody>
<script>
export default {
data(){
return{
cols: [],
options1:[]
}
},
methods:{
getshop(){
var _this=this
return this.$http.get('http://localhost:3000/api/companyproducts') .then(function (response) {
return response.data;
})
},
onClick(){
this.cols.push({
this.options1:this.getshop(), //how i can push getshop return value to select option
qty:0 });
},
},
}
</script>
suppose if my table has 3 value then 3 row getting created along with 3 select option in ShopIdFrom column as show in image now the problem is that when i m try to push the value getting from getshop function into select option. i.e ShopIdFrom select option i does not have any option value .i.e this.cols.push not working for dynamically select option. what i m doing wrong or is there any other way to achieve this

try this hope it will help you
onClick(){
var t;
var _this=this
this.getshop().then(function(value) {
_this.options1= value
});
this.cols.push({
select1:'',
qty:0 });
},

Related

How to avoid warning "mutating a prop directly" using Vue and Laravel

I am using Laravel 7 and Vue.js 2.
I want to pass an eloquent query result from a controller to a Vue.js component (passing through a View and another component).
This is my controller:
$permissions = Permission::select('id')->get();
return view('admin')->with(['permissions'=>$permissions]);
This is my view:
<div id="app">
<admin-panel :permissions="{{ $permissions }}"></admin-panel>
</div>
This is admin-panel component (passing data through props):
<template>
<div>
<admin-operations></admin-operations>
<hr>
<insert-employee :permissions="permissions"></insert-employee></div>
</template>
This is insert-employee component script:
<script>
export default {
components: {
},
props: ['permissions'],
mounted() {
console.log('Component mounted.');
},
computed:{
},
data: function() {
return {
}
},
methods: {
}
}
</script>
This is the select in insert-employee component:
<select required v-model="permissions" class="form-control" id="permissions">
<option v-for="permission in permissions" :value="permission.id" :key="permission.id">
{{ permission.id }}
</option>
</select>
The results of the query should be visualized in the select options.
However in the select I can visualize correctly the values in the options, but when I select an option the selection doesn't work and in the console appears two times the following warning:
app.js:40160 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "permissions"
found in
---> <InsertEmployee> at resources/js/components/InsertEmployee.vue
<AdminPanel> at resources/js/components/AdminPanel.vue
<Root>
Can help?
Let's try this. I think we're just mixing the values up a bit. I'll try to think of props that are passed in as a read only thing. In this case permissions is an array that holds the id's of each permission.
Next we'll want to use that array to give our user object some values. This way we aren't trying to manipulate values of permissions. That's where Vue was initially getting angry.
<script>
export default {
components: {},
props: {
permissions: {
type: Array,
required: true,
default: () => [],
}
},
mounted() {
console.log('Component mounted.');
},
computed:{},
data: () => ({
user: {
permissionId: "",
}
}),
methods: {},
}
</script>
Then in your component template:
<select required v-model="user.permissionId" class="form-control" id="user-permissionId">
<option v-for="permission in permissions" :value="permission.id" :key="permission.id">
{{ permission.id }}
</option>
</select>

How to create private channel name dynamically

I woluld like to create real-time order tracking system using laravel, vue and pusher. In admin panel I have list of all orders. The idea is when admin change order status the user (owner of this order) will get notification without refreshing page. To make it I want to use private channels. My problem is to create private channel name dynamically.
Admin panel looks like below.
<h1>Admin</h1>
<table>
#foreach ($orders as $o)
<tr>
<td>{{$o->name}}</td>
<td>{{$o->status}}</td>
<td>{{$o->getUser->name}}</td>
<td>
<update-order-status :id="{{$o->id}}"></update-order-status>
</td>
</tr>
#endforeach
</table>
There is update-order-status component which is a form used to change status of order. Id of order is passed to component via props. Content of component look like below:
///update-order-status component
<template>
<div>
<form method="GET" action="change_status">
<input type="hidden" name="id" :value=id />
<select name="status">
<option value="placed">Placed</option>
<option value="progres">Progres</option>
<option value="delivered">Delivered</option>
</select>
<input type="submit" value="update status" v-on:click="upd(id)" />
</form>
</div>
</template>
<script>
export default {
created() {
},
props: ["id"],
data: function() {
return {
};
},
methods: {
upd: function(id) {
this.$root.$emit("eve", id);
}
}
};
</script>
When admin submit form order status is updated in database and also event eve is emitted. This event is used to pass id of order to status-changed compoennt. This component is placed in user panel and contains notification that order status has been changed.
///status changed component
<template>
<div v-if="sn" class="notification is-primary">
<button class="delete" v-on:click="del()"></button>
Staus of order nr {{nr}} has been changed
</div>
</template>
<script>
export default {
created() {
this.$root.$on("eve", data => {
this.nr = data;
});
Echo.private("order" + this.nr).listen("status_changed", e => {
this.sn = true;
});
},
props: [],
data: function() {
return {
sn: false,
nr: 0
};
},
methods: {
del: function() {
this.sn = false;
}
}
};
</script>
Here is the problem. Variable nr is 0 all time. It'not changing dynamically. When nr is static or channel is public this code works fine. Please help.
Put the Echo inside the $on. Otherwise the asynchronous $on happens too late to change nr in the Echo.
created() {
this.$root.$on("eve", data => {
this.nr = data;
Echo.private("order" + this.nr).listen("status_changed", e => {
this.sn = true;
});
});
}

Find a matching value in Vue component

I have passed this collection (postFavourite) to my vue component via props.
[{"id":1,"user_id":1,"post_id":2,"created_at":"2018-07-24 09:11:52","updated_at":"2018-07-24 09:11:52"}]
How do I then check if any instance of user_id in the collection is equal to userId which is the current logged in user (also sent via props).
Tried
let pf = _.find(this.postFavourite, { "user_id": this.userId})
Keep getting undefined as the value of the pf variable even though this.userID is equal to 1.
New to JS and Vue.js so any help would be great.
Here is the vue component code.
<template>
<div>
<i v-show="this.toggle" #click="onClick" style="color: red" class="fas fa-heart"></i>
<i v-show="!(this.toggle)" #click="onClick" style="color: white" class="fas fa-heart"></i>
</div>
</template>
<script>
export default {
data() {
return {
toggle: 0,
}
},
props: ['postData', 'postFavourite', 'userId'],
mounted() {
console.log("Post is :"+ this.postData)
console.log("User id is: "+ this.userId)
console.log("Favourite Object is :" +this.postFavourite);
console.log(this.postFavourite.find(pf => pf.user_id == this.userId));
},
methods: {
onClick() {
console.log(this.postData);
this.toggle = this.toggle ? 0 : 1;
}
}
}
</script>
This is how I passed the props to vue
<div id="app">
<favorite :post-data="'{{ $post->id }}'" :post-favourite="'{{Auth::user()->favourite }}'" :user-id="'{{ $post->user->id }}'"></favorite>
</div>
I gave up on lodash and find and just messed around with the data in the chrome console to work out how to check the value I wanted.
Then I built a loop to check for the value.
If it found it toggle the like heart on of not leave it off.
This will not be the best way to solve this problem but I'm just pleased I got my first real vue component working.
<template>
<div>
<i v-show="this.toggle" #click="onClick" style="color: red" class="fas fa-heart"></i>
<i v-show="!(this.toggle)" #click="onClick" style="color: white" class="fas fa-heart"></i>
</div>
</template>
<script>
export default {
props: ['postData', 'postFavourite', 'userId']
,
data() {
return {
toggle: 0,
favs: [],
id: 0
}
},
mounted () {
var x
for(x=0; x < this.postFavourite.length; x++){
this.favs = this.postFavourite[x];
if(this.favs['post_id'] == this.postData) {
this.toggle = 1
this.id = this.favs['id']
}
}
},
methods: {
onClick() {
console.log(this.postData)
if(this.toggle == 1){
axios.post('favourite/delete', {
postid: this.id
})
.then(response => {})
.catch(e => {
this.errors.push(e)
})
}
else if(this.toggle == 0){
axios.post('favourite', {
user: this.userId,
post: this.postData
})
.then(response => {
this.id = response.data
})
.catch(e => {
this.errors.push(e)
})
}
this.toggle = this.toggle ? 0 : 1;
}
}
}
</script>
Where I pass my props.
<favorite :post-data="'{{ $post->id }}'"
:post-favourite="{{ Auth::user()->favourite }}"
:user-id="'{{ Auth::user()->id }}'"></favorite>
Thanks to all that tried to help me.
From just the code you provided, I see no issue. However lodash is not required for this problem.
Using ES2015 arrow functions
let pf = this.postFavourite.find(item => item.user_id === this.userId);
Will find the correct item in your array
You can read more about this function in the mdn webdocs
You can use find() directly on this.postFavourite like this:
this.postFavourite.find(pf => pf.user_id == this.userId);
Here is another way to do it that might help you as well.
[EDIT]
In order to use find() the variable needs to be an array, this.postFavourite is sent as a string if you didn't use v-bind to pass the prop thats what caused the error.
To pass an array or an object to the component you have to use v-bind to tell Vue that it is a JavaScript expression rather than a string. More informations in the documentation
<custom-component v-bind:post-favourite="[...array]"></custom-component>

How to filter comments with vue.js?

In my view i have this :
<select class="sort_by">
<option selected disabled>SORT BY</option>
<option value="name" >Name</option>
<option value="date">Date</option>
</select>
In my controller i have this:
$comments = $article->comments()->orderBy('created_at','desc')->get();
In my vue i have this:
loadComments: function () {
articleid = this.article_id;
this.$http.get('/article/'+ articleid +'/allcomments').then(function(response){
// True
data = response.data.comments;
this.$set('all_comments', data);
this.comments= data;
}, function(response){
// False
});
},
What i want is when user select name or date, to change orderBy and then to display it in view without refresh. Any suggestion how can i do that?
EDIT:
In my ready function i have:
this.loadComments();
setInterval(function () {
this.loadComments();
}.bind(this), 20000);
So i cant sort by in vue.js, or can i?
You can use the Lodash sortBy method inside a computed property which acts as a filter. Lodash is included by default in the newest Laravel versions.
Your .vue file could look like this:
(NOTE: This is a Vue 2.0 example, if you are using a previous version of Vue some things can differ)
<template>
<select v-model="sortingBy" class="sort_by">
<option selected disabled>SORT BY</option>
<option value="name">Name</option>
<option value="date">Date</option>
</select>
<div v-for="comment in sortedComments">
// Here your HTML for each comment
<div>
</template>
<script>
export default {
data() {
return{
comments: {},
sortingBy: "name", // Default sorting type
}
},
computed: {
sortedComments: function () {
return _.sortBy(this.comments, [this.sortingBy]);
}
},
mounted() {
this.loadComments();
setInterval(function () {
this.loadComments();
}.bind(this), 20000);
},
methods: {
loadComments: function () {
this.$http.get('/article/' + this.article_id + '/allcomments').then((response) => {
this.comments = response.data;
});
},
}
}
</script>

Knockout select attr:{title Binding} not working as expected for Observable array

I want show the title(walk,run,talk) based on select value when mouseOver on particular options.
Here Is my Fiddle
Is this a bug in knockout (or) Am I doing Wrong?
HTML:-
<select data-bind="value: activityId,optionsValue: 'id', optionsText: 'name', options: activityArray,optionsCaption:'Select',attr: {title:'name'}">
Script
// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel() {
var self = this;
self.activityId = ko.observable("");
self.activityArray = ko.observableArray();
self.activityArray.push(new Activity(1,'walk'));
self.activityArray.push(new Activity(2,'run'));
self.activityArray.push(new Activity(3,'talk'));
}
function Activity(id,name){
this.id = id;
this.name = name;
};
// Activates knockout.js
ko.applyBindings(new AppViewModel());
Any help is appreciable
If you want to have additional attributes on the generated options elements you cannot use the options binding you have to do it "manually" with foreach
<select data-bind="value: activityId">
<option>Select</option>
<!-- ko foreach: activityArray -->
<option data-bind="value: id, text: name, attr: {title: name}"></option>
<!-- /ko -->
</select>
If you want to display the a title also for the currently selected element you will need a computed observable which calculates the title from the activityId:
self.selectedActivity = ko.computed(function () {
var selected = ko.utils.arrayFirst(self.activityArray(), function (item) {
return item.id == self.activityId()
});
if (selected)
return selected.name;
});
Then you can use this selectedActivity on your select:
<select data-bind="value: activityId, attr: {title: selectedActivity}">
Demo JSFiddle.
Another solution could be this: http://jsfiddle.net/un2qh/3/
HTML:
<select data-bind="options: activityArray, optionsText: 'name',
value: selectedActivity, attr: {title: activityTitle},
optionsCaption: 'Choose...', optionsAfterRender: setOptionTitle">
</select>
JS (main computed attribute for title):
self.activityTitle = ko.computed(function () {
return self.selectedActivity() ? self.selectedActivity().name : "" ;
});

Resources