Vue JS Props are undefined - javascript

I'm trying to use props in my methods in Vue.js
<login opendiv="password" rid="123"></login>
const app = new Vue({
el: '#app',
props: {
opendiv: String,
rid: String,
},
components: {
'login': {
data() {
return {
mode: this.opendiv,
email: "",
username: "",
password: "",
confirmPassword: "",
}
},
template: `<div>
...
</div>`,
mounted() {
console.log(this.opendiv, this.rid);
},
mode and the console.log always return undefined

Related

Vue.js update parent data with an input from a child component

I'm using Vue.js 2 and I'm trying to update the description of a file using an input in a child component. I've been reading a few related questions and read some of the official docs along with .sync but I'm struggling to get the result I want since files is a list of objects.
Here's what I've been trying.
Vue.component('myComponent', {
props: ["file"],
data() {
return {
myDescription: '',
}
},
mounted() {
this.myDescription = this.file.description;
},
template: `
<div>
<label>{{ file.name }}</label>
<br>
<input type="text" #input="update" :value="myDescription"></input>
<br><br>
</div>
`,
methods: {
update() {
this.$emit("update-description", this.myDescription, this.file);
},
}
})
var app = new Vue({
el: '#app',
methods: {
updateDescription(description, file) {
console.log(description);
}
},
data: {
files: [{
id: 1,
name: "Hello",
description: "",
},
{
id: 2,
name: "World",
description: "Foo",
},
{
id: 3,
name: "John",
description: "Bar",
}
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div> {{ files }} </div>
<br>
<my-component v-for="file in files" :key="file.id" :file="file" #update-description="updateDescription" />
</div>
You're almost there, you can see in the code you've provided that the child component event is being emitted but the value is empty. The problem is you're not updating myDescription, if you change your :value to v-model then it will update, as v-model uses two way binding.
Also, if you want to update the file description, you can just do:
file.description = description;
Vue.component('myComponent', {
props: ["file"],
data() {
return {
myDescription: '',
}
},
mounted() {
this.myDescription = this.file.description;
},
template: `
<div>
<label>{{ file.name }}</label>
<br>
<input type="text" #input="update" v-model="myDescription"></input>
<br><br>
</div>
`,
methods: {
update() {
this.$emit("update-description", this.myDescription, this.file);
},
}
})
var app = new Vue({
el: '#app',
methods: {
updateDescription(description, file) {
console.log(description);
file.description = description;
}
},
data: {
files: [{
id: 1,
name: "Hello",
description: "",
},
{
id: 2,
name: "World",
description: "Foo",
},
{
id: 3,
name: "John",
description: "Bar",
}
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div> {{ files }} </div>
<br>
<my-component v-for="file in files" :key="file.id" :file="file" #update-description="updateDescription" />
</div>

Convert an array to a component in React

In the project there is an array of objects used for populating the breadcrumb:
export const BREADCRUMBS_LIST = [
{ label: 'Home', path: '/', active: false },
{ label: 'Account', path: '/accounts', active: false },
{ label: 'This Account', path: '/accounts', active: true }
];
it is used to populate the list in the Breadcrumbs component:
import { BREADCRUMBS_LIST } from './...'
...
<Breadcrumbs list={BREADCRUMBS_LIST} />
Everything works fine.
The problem appears when we need to translate those labels based on the user's language. For this, we are using react-intl.
So, I transformed the original array into a component of this form:
import { useIntl } from 'react-intl';
export const BreadcrumbsList = () => {
const intl = useIntl();
return [
{ label: intl.formatMessage({ id: 'Home' }), path: '/', active: false },
{
label: intl.formatMessage({ id: 'Account' }),
path: '/accounts',
active: false
},
{
label: intl.formatMessage({ id: 'This Account' }),
path: '/accounts',
active: true
}
];
};
and use it like this:
<Breadcrumbs list={BreadcrumbsList} />
it seems to be wrong because it returns an error saying:
Cannot read property 'map' of undefined.
In that component, the list was used with map: {list.map(({path, label, active}, index) => {...})
Any ideas how to solve this problem?
Your BreadcrumbsList is actually a custom hook, in order to stick with the Rules of Hooks you need to call it on component's level:
// Add "use" prefix as its a custom hook
const useBreadcrumbsList = () => {
const intl = useIntl();
return [
{ label: intl.formatMessage({ id: "Home" }), path: "/", active: false },
{
label: intl.formatMessage({ id: "Account" }),
path: "/accounts",
active: false,
},
{
label: intl.formatMessage({ id: "This Account" }),
path: "/accounts",
active: true,
},
];
};
// Usage
const Component = () => {
const breadcrumbsList = useBreadcrumbsList();
return <Breadcrumbs list={breadcrumbsList} />;
};

I am migrating from apollo-link-state to #apollo/client, how do I write default data to InMemoryCache of #apollo/client without using cache.writeData?

I use react 16.13 and am currently migrating from apollo-client 2.x to #apollo/client 3.1.1. I removed a lot of dependency libraries from my packages.json because most of them are now directly importable from #apollo/client. Everything was going fine until I tossed a big rock named "removal of defaults" while migrating from apollo-link-state.
With #apollo/client 3.x, we import InMemoryCache from #apollo/client directly, which is fine. But the withClientState link is no longer existent and ApolloClient doesn't support default values for local cache. I could not find any guide covering this problem. There is one guide for Angular, but it advises to use cache.writeData to construct the cache. Only problem is, in v3.x of #apollo/client, InMemoryCache doesn't have a writeData method anymore. There is a modify method but it is also not straightforward to use, at least I was not able to make it work for this purpose.
I have a large "defaults" object:
export default {
authentication: {
__typename: 'authentication',
auth: ''
},
UserInfo: {
__typename: 'UserInfo',
employee: {
__typename: 'UserInfoEmployee',
defaultShopId: '',
id: '',
email: '',
image: {
__typename: 'image',
id: '',
url: ''
},
firstName: '',
lastName: '',
manager: '',
boss: ''
},
countryCode: '',
chainId: ''
},
defaultShop: {
__typename: 'defaultShop',
id: '',
name: '',
timeZone: null
},
locale: {
__typename: 'locale',
locale: getBrowserLocale()
},
countries: {
__typename: 'countries',
data: []
},
Products: {
__typename: 'Products',
guid: 0,
ProductTypes: {
__typename: 'ProductTypes',
TypeNumber: 0,
type: ''
},
legacyConfiguration: false,
version: '1.0.0'
},
location: {
__typename: 'location',
pathname: '',
search: '',
hash: null,
action: '',
key: null,
isQueryActive: false,
query: null
}
}
How should I write these default data into InMemoryCache without using cache.writeData?
Use writeQuery instead.
I believe in v3 they moved towards using a common way for setting a default state.
Official docs
const query = gql`
query {
authentication #client {
id
__typename
}
...
}`
cache.writeQuery({
query,
data: {
authentication: {
__typename: 'authentication'
...
}
})
it needs to be written using policies, cache.writeQuery didn't work for me at the time of initialization,
cache.policies.addTypePolicies({
Query: {
fields: {
selectedCurrency: {
read() {
return "USD";
},
},
selectedIndex: {
read() {
return 0;
},
},
bookingFlowStep: {
read() {
return '';
},
},
},
},
});

Extending Vue component results in multiple GET calls

I have a Base Vue Component, which handles items. Now i've extended that component with a CompanyItem and a EducationItem. But when i load both the directives, it will call a GET method 4 times. Also: i have a click handler on 2 models (example: openUpdateOrCreateModal()) which is loaded in one of the directives. When i click, the other directive is triggered too. Anyone a idea?
Base
module.exports = {
props: ['user', 'update_url', 'store_url', 'delete_url', 'show_url', 'index_url', 'item_type'],
mounted() {
Bus.$emit('index');
},
data(){
return {
form: {},
items: [],
mainItem: {},
item: {},
}
},
created(){
},
methods: {
resetForm(){
this.form = new SparkForm({
general: {
title: null,
},
item: this.getItemProperties(),
address: {
address_line_1: null,
address_line_2: null,
city: null,
province: null,
zip_code: null
}
});
this.mainItem = null;
},
getItemProperties(){
return {};
},
showModal(){
$('#create-update-'+this.item_type+'-modal').modal('show');
},
hideModal(){
$('#create-update-'+this.item_type+'-modal').modal('hide');
},
/**
* Gets a list with specific items
*/
index(){
console.log('Call index');
axios.get(this.index_url)
.then(response =>
{
this.items = response.data.data;
});
},
}
};
Education
var base = require('./cv-item-base');
Vue.component('cv-educations-management', {
mixins: [base],
methods: {
getItemProperties(){
return {
start_at: null,
end_at: null,
description: null,
finished_education: null,
level: null,
}
}
}
});
Companies
var base = require('./cv-item-base');
Vue.component('cv-company-list', {
mixins: [base],
methods: {
getItemProperties(){
return {
start_at: null,
end_at: null,
position: null,
description: null,
phone_number: null,
branch: null,
referral: null,
}
}
}
});
HTML
<cv-company-management :user="user"
:update_url="'{{route('application.manage.companies.update')}}'"
:show_url="'{{route('application.manage.companies.show')}}'"
:delete_url="'{{route('application.manage.companies.destroy')}}'"
:store_url="'{{route('application.manage.companies.store')}}'"
:index_url="'{{route('application.manage.companies.index')}}'"
:item_type="'company'"
inline-template>
</cv-company-management>
<cv-education-management :user="user"
:update_url="'{{route('application.manage.educations.update')}}'"
:show_url="'{{route('application.manage.educations.show')}}'"
:delete_url="'{{route('application.manage.educations.destroy')}}'"
:store_url="'{{route('application.manage.educations.store')}}'"
:index_url="'{{route('application.manage.educations.index')}}'"
:item_type="'education'"
inline-template>
</cv-education-management>

VueJS How to use parent method from component

From the component I want to access methods of the parent.
(Without props)
Here's the HTML:
<div id="el">
<user v-for="user in users" :item="user"></user>
</div>
Here's the Vue code:
var usersData = [
{ id:1, firstname:'John', lastname: 'Doe' },
{ id:2, firstname:'Martin', lastname: 'Bust' }
];
var vm = new Vue({
el: '#el',
data: { users: usersData },
methods: {
getFullName: function (user) {
return user.id + '. ' + user.firstname + ' ' + user.lastname;
}
},
components: {
user: {
template: '<span>{{ fullName }}</span>',
props: ['item'],
computed: {
fullName: function(){
return this.$parent.getFullName(this.item);
}
},
}
}
});
VueJS version: 2.0.2
Both are this.$parent.$options.methods.getFullName() and this.$parent.methods.getFullName() not working.
For Vue.js version 2.2.0+ you can use dependency injection with inject and provide like this:
HTML:
<div id="el">
<user v-for="user in users" :item="user"></user>
</div>
JavaScript:
var usersData = [
{ id:1, firstname:'John', lastname: 'Doe' },
{ id:2, firstname:'Martin', lastname: 'Bust' }
];
var vm = new Vue({
el: '#el',
data: { users: usersData },
methods: {
getFullName: function (user) {
return user.id + '. ' + user.firstname + ' ' + user.lastname;
}
},
provide: function () {
return {
getFullName: this.getFullName
}
},
components: {
user: {
template: '<span>{{ fullName }}</span>',
inject: ['getFullName'],
props: ['item'],
computed: {
fullName: function(){
return this.getFullName(this.item);
}
},
}
}
});
Fiddle: https://jsfiddle.net/haaiee/v1ahoytm/2/

Categories