How can i assign computed properties to data with Vue.js? - javascript

In my CMS system, I can add pages. I want to also edit the existing content of these pages.
What I am trying to achieve is:
User edits page
Page updates in same firebase document where it was created
Page displays new content
Right now, I have set up getter and setter in computed where getter is getting data from the firebase collection and is providing the corresponding text I want to edit, and setter will commit to the changes I do with this text.
data: () => ({
title: null,
content: null
}),
computed: {
pages: {
get() {
return this.pageIndex
},
set() {
this.title
this.content
}
}
},
To update the document in firebase I am triggering this method:
methods: {
async update(id) {
return db
.collection('PAGES')
.doc(id)
.set({
title: this.title,
content: this.content
})
.then(() => {
return this.fetchPage()
})
},
}
But it posts this in my firebase document:
title: null
content: null
In the console, it shows undefined. When posting the data as with array or objects, it does post whatever changes I made. But that is my problem, I do not want to post it as an object or array, I am trying to post it as field names inside a document.
The current way I am doing it results in this:
What can I change to post the updated title and content?
Edit:
If I do it this way it will post the data but it will post as an object and an array:
data: function() {
return {
updatedPayload: {
title: null,
content: null
}
}
},
computed: {
pages: {
get() {
return this.pageIndex
},
set() {
this.updatedPayload = { title: this.title, content: this.content }
}
}
},
methods: {
async update(id) {
// return db.doc(`pages/${page.id}`)
const self = this
const pages = self.pages
return db
.collection('PAGES')
.doc(id)
.set({ pages })
.then(() => {
return this.fetchPage()
})
}
}
Here is the HTML
<tbody v-for="(page, idx) in pages" :key="page" class="">
<b-input v-model="page.title"></b-input>
<VueEditor v-model="page.content"></VueEditor>
</tbody>
So the dilemma is, I can only update data with an object, but I can not update data with field name, as it appears.
The OP of this thread is trying to achieve the same outcome as me, populate data for an input field, where as input shows existing information, and can populate new data. In my case, I need 2 inputs to populate new data, it already displays existing data from firebase.

Related

Vuejs return data from component to Laravel

I am trying to make a search bar to collect a list of products which the user will then be able to select an array of products and add it to an order.
So far the products can be searched, added to a "products" array via an "add" button and they are able to see the data within products. They are also able to remove products that they do not want.
My issue is that I am trying to send the data from the "products" array with a parent form. The search component is located within the form as well as the list. But I do not know how I would send the array with the form.
I do not need to send the entire product object, but just the ID which will be used to link up the products with the order.
Here is where the component is:
<div class="uk-margin" id="search">
<label for="Search" class="uk-form-label">Search products to add</label>
<search input="ess"></search>
</div>
Here is the vuejs component data:
export default {
data() {
return {
keywords: null,
results: [],
products: []
};
},
watch: {
keywords (after, before) {
this.fetch();
}
},
methods: {
fetch() {
axios.get('/search', { params: { keywords: this.keywords } })
.then(response => this.results = response.data)
.catch(error => {});
},
addProduct (product) {
let duplicate = false;
this.products.forEach((item, index) => {
if (item.ID === product.ID) {
duplicate = true;
}
});
if (!duplicate) {
this.products.push(product);
}
},
removeProduct (product) {
Vue.delete(this.products, product);
}
}
}
Everything works fine, but my question is.. How am I able to pass the data back to the html / laravel to use it while sending data to the controller. I only need to send the "products" array, I have tried using input with the data but it isn't working. Does anyone know how I could do it, or is the best way to do so, using JavaScript and add them to an array by finding all the elements which are being displayed?
Many thanks.

Apollo GraphQL merge cached data

I have a page that consists of 2 components and each of them has its own request for data
for example
<MovieInfo movieId={queryParamsId}/>
const GET_MOVIE_INFO = `gql
query($id: String!){
movie(id: $id){
name
description
}
}`
Next component
<MovieActors movieId={queryParamsId}/>
const GET_MOVIE_ACTORS = `gql
query($id: String!){
movie(id: $id){
actors
}
}`
For each of these queries I use apollo hook
const { data, loading, error } = useQuery(GET_DATA, {variable: {id: queryParamsId}}))
Everything is fine, but I got a warning message:
Cache data may be lost when replacing the movie field of a Query object.
To address this problem (which is not a bug in Apollo Client), either ensure all objects of type Movie have IDs, or define a custom merge function for the Query.movie field, so InMemoryCache can safely merge these objects: { ... }
It's works ok with google chrome, but this error affects Safari browser. Everything is crushing. I'm 100% sure it's because of this warning message. On the first request, I set Movie data in the cache, on the second request to the same query I just replace old data with new, so previous cached data is undefined. How can I resolve this problem?
Here is the same solution mentioned by Thomas but a bit shorter
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
YOUR_FIELD: {
// shorthand
merge: true,
},
},
},
},
});
This is same as the following
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
YOUR_FIELD: {
merge(existing, incoming, { mergeObjects }) {
return mergeObjects(existing, incoming);
},
},
},
},
},
});
Solved!
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
YOUR_FIELD: {
merge(existing = [], incoming: any) {
return { ...existing, ...incoming };
// this part of code is depends what you actually need to do, in my
case i had to save my incoming data as single object in cache
}
}
}
}
}
})
});
The other answers still work, but as of Apollo Client >= 3.3 there's an easier option that doesn't require specifying specific fields or a custom merge function. Instead, you only have to specify the type and it will merge all fields for that type:
const cache = new InMemoryCache({
typePolicies: {
YOUR_TYPE_NAME: {
merge: true,
}
}
});
From your example query, I'd guess that an id field should be available though? Try requesting the ID in your query, that should solve the problem in a much more ideal way.
Had same issue with inconsistency of data values vs. our schema. A value type within an entity was missing the id value. Caused by an incomplete data migration.
Temporary solution:
const typePolicies = {
PROBLEM_TYPE: {
keyFields: false as false,
},
PARENT_TYPE: {
fields: {
PROBLEM_FIELD: {
merge: true
}
}
}
}

VueJs - Pushing created item to existing array and having it display with the other existing items

I'm executing a POST request using Vue to insert a new record to the database. This is working as expected and the next target is to have the newly created item pushed to the existing array and have it display in a table. This is being done in a Vue component.
This is the form that is being submitted:
<form #submit.prevent="createUser">
This is the javascript part:
export default {
data(){
return{
users: {},
form: new Form({
name: '',
email: '',
password: '',
type: '',
bio: '',
photo: '',
})
}
},
methods:{
displayUsers(){
axios.get('api/user').then( ({data}) => (this.users = data) )
},
createUser(){
this.form.post('api/user').then( ({ data }) =>
this.users.push(data.data)
);
}
},
created() {
this.displayUsers();
}
}
From the createUser method, the entry is posted to the database and the created entry pushed to the existing users array. My backend code returns this data i.e.
return response()->json(['data' => $request->all()], 200);
Was thinking this would be enough to get the new entry to display on the table automatically without refresh as the users array has been updated but this is not happening.
The table displaying all the items looks like this:
<tr v-for="user in users" :key="user.id">
<td>{{ user.id }}</td>
....
So what I'm i missing? Is there an extra step needed for my freshly created entry to be pushed automatically to my table?
Try this -
In the createUser method, when you are assigning the newly created user, avoid mutation.
createUser(){
this.form.post('api/user').then( ({ data }) =>{
this.users = [ ...this.users, data.data ];
});
}
This will help vue identify that the list has changed as we are assigning an entirely new array to users everytime a new user is created.
The push method modifies the same array. The spread operator helps avoid this mutation as we are copying all users in the new array along with newly created user.

Array of Empty Objects vs Array of Objects - Firebase and Polymer

I'm trying to use the Polymer Shop template to create an online store, replacing the standard category objects with objects from Firebase Cloud Firestore. After initializing the database, I'm trying to use the objects to show a list of categories in a drawer menu.
This top example is with Cloud Firestore. As well as the code, you can see via screenshot what the console prints out when categoryList is console logged.
Cloud Firestore Console Output
let categoryList = []
firebase.firestore().enablePersistence()
.then(function() {
// Initialize Cloud Firestore through firebase
var db = firebase.firestore();
db.collection("product-categories").where('active', '==', true)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
categoryList.push(doc.data())
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
});
Here's the code in the original Polymer Shop template, as well as a screenshot showing the output when categoryList is printed to the console.
Polymer Shop Template Console Output
(function() {
let categoryList = [
{
name: 'oils_and_tinctures',
title: 'Oils and Tinctures'
},
{
name: 'concentrates',
title: 'Concentrates'
},
{
name: 'Vape',
title: 'Vape'
},
{
name: 'topicals',
title: 'Topicals'
},
{
name: 'pet_products',
title: 'Pet Products'
}
];
It seems like I need an array of empty of objects and then to fill those objects. How do I get the data from Firebase Cloudstore to match the format of the original template data?
Thanks in advance for anyone's help!
querySnapshot.forEach(function (doc) => {
categoryList.push({ name: doc.name, title: doc.title })
}).
OR
function CategoryData(name, title) {
this.title = title;
this.name = name;
}
querySnapshot.forEach(function (doc) => {
categoryList.push(new CategoryData(doc.name, doc.title))
})
Using the second way you can define what ever structure you like.

Angular 2 display newly added item to http in other component

This is probably easy for someone, but I just can't get it. So I have a list of items to display:
My service that fetches the data, configService.ts
ngOnInit() {
getConfig(): Observable<any> {
return this.http.get<any>('/api/config').map(res => res);
}
}
My savedSearhes component that populates data in the ngFor:
this.configService.getConfig().subscribe(data => {
this.userSavedSearches = data.isr.me.savedSearches //get an array of items
});
the html to display data:
<div *ngFor="let savedsearch of userSavedSearches">
{{savedsearch.name }}
</div>
The main issue I have, is I have another component that I use to add a new item to the same server.
saveSearch() {
this.saveSearchObject = {
name: this.SearchName,
description: this.SearchDescription,
context: this.theContext,
}
this.searchService.createSavedSearch(this.saveSearchObject).subscribe(data => {
console.log(data) // newly added item to server
})
}
The service that posting new item to server:
createSavedSearch(search: SavedSearch): Observable<SavedSearch> {
return this.http.post<SavedSearch>('/api/searches/', search)
}
When I add a new item, the item actually gets added to the server. But I don't see the "savedSearches" component display added item, only when I reload the page I can see new item added.
How to add new item to the server and see its being added with new item in other component without reloading the page.
You can achieve it by Creating a subject where saveSearch function lies
let subjectUserSavedSearches = new Subject();
let obsrvUserSavedSearches = subjectUserSavedSearches.AsObservable();
saveSearch() {
this.saveSearchObject = {
name: this.SearchName,
description: this.SearchDescription,
context: this.theContext,
}
this.searchService.createSavedSearch(this.saveSearchObject).subscribe(data => {
this.userSavedSearches = data;
this.subjectUserSavedSearches.next(this.userSavedSearches);
})
}
Now watch that obsrvUserSavedSearches on the component you need to show data.
The best way is to move methods getConfig() and saveSearch() in a service and just create a subject for userSavedSearches and an Observable to watch the same.
You won't see it unless you do a getConfig() again. Use a .switchMap() to chain your http calls.
saveSearch() {
this.saveSearchObject = {
name: this.SearchName,
description: this.SearchDescription,
context: this.theContext,
}
this.searchService.createSavedSearch(this.saveSearchObject)
.switchMap(data => {
console.log(data) // newly added item to server
return this.configService.getConfig();
})
.subscribe(data => {
this.userSavedSearches = data.isr.me.savedSearches //get an array of items
})
}
Otherwise, unless your savedSearches() actually returned a newly refreshed list, you can do it in your subscribe:
saveSearch() {
this.saveSearchObject = {
name: this.SearchName,
description: this.SearchDescription,
context: this.theContext,
}
this.searchService.createSavedSearch(this.saveSearchObject).subscribe(data => {
this.userSavedSearches = data
})
}

Categories

Resources