I have defined the function in my vue js file but it is giving me error for nameWithLang() function Please have a look
My Form
<multiselect v-model="selected" track-by="id" label="name" :options="options" :loading="isLoading" :internal-search="false" #search-change="getData" :multiple="true" :close-on-select="false" :hide-selected="true":internal-search="false" name="books[]" :show-labels="false" :custom-label="nameWithLang"></multiselect>
My vue js file
import AppForm from '../app-components/Form/AppForm';
Vue.component('coupon-form', {
mixins: [AppForm],
data: function() {
return {
form: {
name: '' ,
description: '' ,
valid_from: '' ,
valid_till: '' ,
discount: '' ,
enabled: false,
books: [],
},
isLoading: false,
options: [],
selected: [],
}
},
methods: {
nameWithLang({ name, sku }) {
return `${name} — ${sku}`
},
getData(query){
this.isLoading = true;
axios.post('/admin/books/find/'+query)
.then((response) => {
this.options = response.data;
this.isLoading = false;
})
.catch((error) => {
this.isLoading = false;
});
},
},
watch: {
selected (newValues) {
this.form.books = newValues.map(obj => obj.id)
}
}
});
Other properties and functions are working nameWithLang is not working
It gives me error this
Property or method "nameWithLang" is not defined on the instance but referenced during render.
why not you just return the value into a variable in data, and set the function into mounted/watch instead using the function to get the value.
just for refer, you can make the script like this :
import AppForm from '../app-components/Form/AppForm';
Vue.component('coupon-form', {
mixins: [AppForm],
data: function() {
return {
form: {
name: '' ,
description: '' ,
valid_from: '' ,
valid_till: '' ,
discount: '' ,
enabled: false,
books: [],
},
isLoading: false,
options: [],
selected: [],
newName: '',
}
},
methods: {
nameWithLang({ name, sku }) {
this.newName = `${name} — ${sku}`;
},
getData(query){
this.isLoading = true;
axios.post('/admin/books/find/'+query)
.then((response) => {
this.options = response.data;
this.isLoading = false;
})
.catch((error) => {
this.isLoading = false;
});
},
},
watch: {
selected (newValues) {
this.form.books = newValues.map(obj => obj.id)
this.nameWithLang();
}
}
});
then you can make the template like this:
<multiselect v-model="selected" track-by="id" label="name" :options="options" :loading="isLoading" :internal-search="false" #search-change="getData" :multiple="true" :close-on-select="false" :hide-selected="true":internal-search="false" name="books[]" :show-labels="false" :custom-label="newName"></multiselect>
this is just another way you can make it and the way i'm understand what actually you want to do. you want to pass the name with lang value into the :custom-label right? so why not just defined one more variable and add the value into the variable. so you just need to pass the value instead the function. in v-bind it's more appropiate to pass a property instead of a method
Related
So what i'm trying to do is pretty simple but for some reason is not working please let me show you.
This is my navigation bar written in vue js and here i'm holding almost all my vue components.
Navigation.vue
<template>
<single-video :user_id="user_id" :video="this.video" :videoUser="this.videoUser"
:videoOptions="videoOptions"></single-video>
</template>
<script>
export default {
name: "Navigation",
data: function () {
return {
user_id: user_id,
// isLogin: isLogin,
video: {},
videoUser: {},
videoOptions: {
autoplay: true,
controls: true,
sources: [
{
src: "",
type: "application/x-mpegURL"
}
]
}
}
},
methods: {
openVideoModal(video){
this.videoOptions.sources[0].src = 'storage/videos/' + video.id + '/' + video.id + '.m3u8';
axios.get('video/' + video.channel_id).then(response => {
this.videoUser = response.data;
}).catch(error => {
if (error.response.status == 422) {
this.errors = error.response.data.errors;
}
console.log('Error');
});
this.video = video;
$('#singleVideo').modal('show');
},
},
}
</script>
In one of my child component i have this method which calling openVideoModal() function in navigation. With the video id. So far it's working.
<a #click="$parent.openVideoModal(video)">
This one is my single video component which display the video itself.And is in modal ("singleVideo" modal)
single-video.vue
<video v-if="this.video"
ref="videoPlayer"
id="my-video"
class="video-js vjs-default-skin vjs-big-play-centered"
controls
preload="auto"
width="749"
height="421"
:poster="this.video.thumbnail"
data-setup="{}">
</video>
<script>
import videojs from 'video.js';
export default {
props: ['user_id', 'video', 'videoUser', 'videoOptions'],
data: function () {
return {
errors: {},
singleVideo: {},
player: null
}
},
mounted() {
if(this.videoOptions.sources[0].src) {
this.player = videojs(this.$refs.videoPlayer, this.videoOptions, function onPlayerReady() {
})
}
},
methods: {
beforeDestroy() {
if (this.player) {
this.player.dispose()
}
}
}
</script>
Please don't delete my question it is very important to me to solve this. I'm going nuts over it. :(
I am trying to build a GPS-Tracker using react-map-gl and want to draw a line with the data retreived from the where-is-iss-API. If the coordinates in the source JSON are initilized staticaly the line is shown.
const [geojson, setGeojson]: any = useState(
{
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[-77.0323, 38.9131],
[-80.0323, 40.9131]
]
},
properties: {
"name": "Route"
}
});
but when addind data via useEffect it isn't displayed
const [data, setData]: any = useState(dataProp);
const updateLayer = () => {
console.log(data)
if (data.latitude !== undefined && data.longitude !== undefined) {
setGeojson({
...geojson,
geometry: {
coordinates: [
...geojson.geometry.coordinates,
[data.longitude, data.latitude]
]
}
})
}
console.log(geojson);
}
useEffect(() => {
setData(dataProp);
if(data !== undefined && data !== null){
updateLayer();
}
}, [dataProp]);
In this case the line is only displayed for the first two coodinates.
const route: LayerProps = {
id: 'route',
type: 'line',
source: 'geojson',
paint: { 'line-color': 'red', "line-width": 4 }
};
return (
<div>
<ReactMapGL
{...viewport}
mapboxApiAccessToken={token}
mapStyle={"mapbox://styles/gobsej/ckomzwjdg377w18ozdhm1by36"}
width="100vw"
height="100vh"
onViewportChange={(viewport: React.SetStateAction<{ latitude: number; longitude: number; zoom: number; }>) => setViewport(viewport)}
>
<Source id="my-data" type="geojson" data={geojson}>
<Layer {...route} />
</Source>
</ReactMapGL>
</div >
);
The data is retreived with axios and given to the component as a prop
const getGPSLocation = async () => {
await Axios.get('https://api.wheretheiss.at/v1/satellites/25544').then((response) => {
console.log(response.data);
setData(response.data);
}).catch((error) => {
console.log(error);
});
};
useEffect(() => {
getGPSLocation();
const interval = setInterval(getGPSLocation, 1000)
return () => {
clearInterval(interval); }
}, []);
return (
<div>
<Map dataProp={data}></Map>
</div>
);
The console output is the following:
https://i.stack.imgur.com/oZIlb.png
I am using Vue.js 2 and Laravel 7.
I want to pass some errors from the child component to the parent controller. But for some reasons emit did not work.
This is the method of the child component AllocateTask:
methods: {
assignTask: function() {
this.form.task_id = this.user.tasks;
this.form.user_id = this.dev.id;
alert(this.form.task_id);
alert(this.form.user_id);
axios.post('/ticketsapp/public/api/store_task_user', this.form)
.then((response) => {
console.log(response.data);
alert('ok');
this.errors = response.data;
alert(Object.keys(this.errors).length);
if (Object.keys(this.errors).length === 0) {
alert('viva');
} else {
alert('noviva');
this.$emit('failure');
this.$emit('pass-errors', this.errors);
}
})
.catch(error => {
alert('no ok');
console.log(error);
});
}
}
This is the parent component TheReporterTickets:
<template>
<div>
<allocate-task :dev="dev" :tasks="tasks" #pass-errors="onPassErrors" #failure="displayErrors=true" #success="displaySuccess=true"></allocate-task>
<hr>
<validated-errors :errorsForm="errorsTicket" v-if="displayErrors===true"></validated-errors>
</div> </template>
<script>
import AllocateTask from "./AllocateTask.vue"
import ValidatedErrors from "./ValidatedErrors.vue"
export default {
components: {
'allocate-task': AllocateTask,
'validated-errors': ValidatedErrors
},
props: {
dev: {
type: Array,
required: true,
default: () => [],
},
tasks: {
type: Array,
required: true,
default: () => [],
}
},
mounted() {
console.log('Component mounted.');
},
data: function() {
return {
displayErrors: false,
errorsTicket: []
}
},
methods: {
onPassErrors(value) {
alert('error');
console.log('errors passed');
const values = Object.values(value);
this.errorsTicket = values;
console.log(this.errorsTicket);
}
}
} </script>
As you can imagine, I am unable to call the method onPassErrors located in the parent component. I visualize correctly the alert in the else statement of the child component, so I suppose that I am unable to pass the data from the child to the parent component.
Can help?
I got an vue-warning (which results to as an error on my end coz my code is not working) that says:
[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: "editmode"
With it, tried the suggestion here but can't make it work. Below is my work:
props:{
editmode:{
type: Boolean,
default: false,
}
},
methods:{
toggleM(){
var editmode = this.editmode;
editmode = !editmode;
this.editmode = editmode;
if(editmode == false){
//dothis
}else{
//dothat
}
},
}
TEMPLATE
<template>
<div class="ui-table-container-body">
<div class="ui-table" v-if="Boolean(items.length) || Boolean(Object.keys(items).length)" v-cloak>
<ui-table-body ref="body" v-model="items"
:editmode="editmode"
>
</ui-table-body>
</div>
</div>
</template>
The line this.editmode = editmode; is the one pointed in my console, is there any way I can surpass this?
You must use a data variable as a gateway to your prop.
In your component, the code code should look like this:
props:{
editmode:{
type: Boolean,
default: false,
}
},
data: {
dataEditMode = false
},
watch: {
'editmode': {
handler: 'onEditmodeChanged',
immediate: true,
},
'dataEditMode': {
handler: 'onDataEditModeChanged'
}
},
methods:{
toggleM(){
var editmode = this.dataEditMode;
editmode = !editmode;
this.dataEditMode = editmode;
if(editmode == false){
//dothis
}else{
//dothat
}
},
onEditmodeChanged (newVal) {
this.dataEditMode = newVal
},
onDataEditModeChanged (newVal) {
this.$emit('editmodeChanged', newVal)
}
}
and the the inclusion of this component in your parent-component should look like this:
<my-component-name :editmode="editmode" #editmodeChanged="(e) => { editmode = e }"></my-component-name>
You shouldn't mutate props from the component itself. See the One Way Data Flow section of the guide. You can use a prop as the initial value, and then keep a value in the data section and mutate that:
props: {
editmode: {
type: Boolean,
default: false,
}
},
data () {
return {
emode: this.editmode,
}
},
methods: {
toggleM () {
let editmode = this.emode;
editmode = !editmode;
this.emode = editmode;
if (editmode == false) {
// dothis
} else {
// dothat
}
},
}
Demo
Vue.component('editbox', {
template: '<div>' +
'<button #click="toggleM">{{ btext }}</button>' +
'<input v-if="emode" />' +
'</div>',
props: ['editmode'],
data () {
return {
emode: this.editmode,
}
},
computed: {
btext () {
return this.emode ? "Text" : "Edit";
}
},
methods:{
toggleM() {
this.emode = !this.emode;
},
}
})
var app = new Vue({
el: '#app',
data: {
mode: true,
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<editbox :editmode="mode" />
</div>
I would send back an event to the parent so it could modify its value:
For example (not tested):
Child Component
props:{
editmode:{
type: Boolean,
default: false,
}
},
methods:{
toggleM(){
var editmode = !this.editmode;
this.$emit('changeEditMode', editmode);
if (editmode == false){
//dothis
} else {
//dothat
}
},
}
Parent
<child-component #changeEditMode="editModeChanged" :editmode="editmode"></child-component>
...
methods:{
editModeChanged(value){
this.editmode = value
},
}
I've recently started to study reactjs and I'm currently experimenting with ajax requests and passing properties from parent to children. I have a react component Competitions which performs an ajax request:
var Competitions = React.createClass({
getInitialState: function() {
return {
compData: [],
}
},
componentDidMount: function() {
axios.get(this.props.source, {
headers: {'X-Auth-Token': '*******************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({compData: result.data});
})
.catch(error => {
console.log(error);
});
},
render: function() {
return (
<CompTable compData={this.state.compData} />
);
}
});
module.exports = Competitions;
The Competitions component passes the results data to CompTable
var CompTable = React.createClass({
propTypes: {
compData: React.PropTypes.array.isRequired
},
handleClick: function(e) {
var url = 'http://api.football-data.org/v1/competitions/x/teams';
var source = url.replace(url.split('/')[5], e);
console.log(source);
},
render: function() {
var list = this.props.compData.map(function (comp, i) {
return (
<tr key={i+1}>
<th scope="row">{i+1}</th>
<td className={comp.id} onClick={this.handleClick.bind(this, comp.id)} >{comp.caption}</td>
</tr>
);
}, this);
return (
<tbody>{list}</tbody>
)
}
});
module.exports = CompTable;
This is the Teams component
var Teams = React.createClass({
getInitialState: function() {
return {
teamData: [],
}
},
componentDidMount: function() {
axios.get(this.props.source, {
headers: {'X-Auth-Token': '*******************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({teamData: result.teams.data});
})
.catch(error => {
console.log(error);
});
},
render: function() {
return (
<TeamsTable teamData={this.state.teamData} />,
);
}
});
module.exports = Teams;
What I'm trying to do is take on click the compData.id property of the CompTable component with a handleClick function and use it as a source property on another component named Teams (identical with the Competitions component) that uses the given property as a source url in order to perform a new ajax request. Is there a way to do that? Thank you
I think I found a solution to my problem.
So, Competitions is the Parent and CompTable and Teams are the children. I don't know if there is a simpler way, but this one seems to work. It's not perfect, I have other problems to solve, but I managed to make a second ajax call inside a child component using my first ajax call inside the parent component, by grabbing the compData.id property and passing it to the children, on click. Any comments are welcome.
Competitions component
var Competitions = React.createClass({
getInitialState: function() {
return {
compData: [],
id: "",
}
},
componentDidMount: function() {
axios.get(this.props.source, {
headers: {'X-Auth-Token': '********************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({compData: result.data});
})
.catch(error => {
console.log(error);
});
},
changeId: function (newId) {
this.setState({
id: newId
});
},
render: function() {
return (
<CompTable compData={this.state.compData} id={this.state.id} onClick= {this.changeId} />
);
}
});
module.exports = Competitions;
CompTable component
var CompTable = React.createClass({
propTypes: {
compData: React.PropTypes.array.isRequired
},
getInitialState: function() {
return {
showTeams: false,
hide: false,
};
},
teamsClick: function() {
this.setState({
showTeams: true,
hide: true,
});
},
handleClick: function(e) {
this.props.onClick(e);
},
render: function() {
var list = this.props.compData.map(function (comp, i) {
return (
<tr key={i+1}>
<th scope="row">{i+1}</th>
<td className={comp.id} onClick={function() { this.teamsClick(); this.handleClick(comp.id); }.bind(this)}> {comp.caption} </td>
<td>{comp.league}</td>
<td>{comp.numberOfTeams}</td>
</tr>
);
}, this);
return (
<div > { this.state.showTeams ? <Teams id={this.props.id}/> : null } </div>
<tbody>{list}</tbody>
)
}
});
module.exports = CompTable;
Teams component
var Teams = React.createClass({
getInitialState: function() {
return {
teamData: [],
}
},
componentDidMount: function() {
var url = 'http://api.football-data.org/v1/competitions/x/teams';
var source = url.replace(url.split('/')[5], this.props.id);
axios.get(source, {
headers: {'X-Auth-Token': '********************',
'Content-type': 'application/json'}
})
.then(result => {
this.setState({teamData: result.data.teams});
})
.catch(error => {
console.log(error);
});
},
render: function() {
return (
<TeamsTable teamData={this.state.teamData}/>
);
}
});
module.exports = Teams;