Passing async 'hasMany' relation to a component - serialization

i have an Ember model with a 'hasMany' relation which i don't want to embed, and i need to pass it asynchronously to a component that gets records from the relation. but when i call the component from emblem file (=user-answer userAnswers=userAnswers id=smth.id), i get an error like "no method 'get' for undefined".
here is the code:
app/models/quiz_progress.coffee:
`import DS from "ember-data";`
`import ProgressMixin from "../mixins/progress_mixin"`
QuizProgress = DS.Model.extend ProgressMixin,
userAnswers: DS.hasMany 'user_answer', async: true
`export default QuizProgress;`
app/components/user-answer.coffee:
`import Ember from "ember";`
UserAnswerComponent = Ember.Component.extend
tagName: 'div'
classNames: ['ui', 'list']
userAnswer: (->
id = #get('id')
answers = #get('userAnswers')
answers.findBy('questionId', id).get('answers')
).property('id', 'userAnswers')
`export default UserAnswerComponent;`
and it works only when userAnswers is serialized as embedded. is there really no way to get rid of embedding? i want to pass ids only

Related

At what stage to process data with the API (vuex)?

I work with pagination in the store and has small question.
Example of information returned from the back:
{last_page: 5, current_page: 1, per_page: 10, total: 100, count: 100, url: 'xyz.com'}
The view to which I will transform this information :
{LastPage: 5, currentPage: 1} // other fields are not needed
I call an action, make a request to the api in it, and get the result from the back containing the fields I don't need. I have to process it. Where is it more correct to do this? Pass the full object to the mutation and already process it in the mutation, or do the mutation in such a way that it would require an already prepared object and, accordingly, process this object in the action, and then throw its "beautiful" version into the mutation?
You should look into creating some models to handle situations like this.
In your model add the things you care about, like this:
export class PageData {
constructor(dto = {}) {
this.lastPage = dto.lastPage || '';
this.currentPage = dto.currentPage || '',
}
}
export default {
PageData,
}
Then in your store import the model like this: import {PageData} from './models.js'
Then simply pass your backend data into your new model when you commit the mutation like this:
commit('setPageData', new PageData(dtoFromBackend))

Getting a payload after calling 'update' method of CartEntryConnector

I used 'updateEntry' method of ActiveCartService for updating the entry of the Cart. After then 'updateEntry$' effect from the CartEntryEffects class was triggered that returned new action.
updateEntry$: Observable = this.actions$.pipe(
ofType(CartActions.CART_UPDATE_ENTRY),
map((action: CartActions.CartUpdateEntry) => action.payload),
concatMap(payload =>
this.cartEntryConnector
.update(payload.userId, payload.cartId, payload.entry, payload.qty)
// should be my logic with payload
.pipe(
map(() => {
return new CartActions.CartUpdateEntrySuccess({
userId: payload.userId,
cartId: payload.cartId,
});
}),
Which is the proper way to get this payload?
Or can I override this effect or add my logic to it?
It depends what you are trying to do with the payload.
If you want to process it before the details get updated into Commerce, then that is generally handled by connectors & adapters. See https://sap.github.io/spartacus-docs/connecting-to-other-systems/
If you want to reference the updated entry & display it, then you can get hold of an Observable via the ActiveCartService. See for example the AddToCart component (https://sap.github.io/spartacus/components/AddToCartComponent.html#source) which declares cartEntry$: Observable<OrderEntry> and then in ngOnInit() does this.cartEntry$ = this.activeCartService.getEntry(this.productCode)

V-select bug while selecting elements in Vuejs

I'm building a small application in vuejs 2 where I'm using v-select package for select box, Problem I'm facing is:
I've declared v-select in my component something like this:
<div class="form-group"><label class="col-sm-2 control-label">Company name:</label>
<div class="col-sm-6">
<v-select :options="companyOptions" v-model="company_name" :on-search="getOptions" placeholder="Company name"></v-select>
</div>
</div>
So accordingly I'm having data defined as company_name, and I'm calling an axios event to get the searchable data, while the component is being loaded I'm calling index data of first 50 set for initial selection and if anybody types then I'm calling a function getOptions to get data related to the input, now suppose if somebody selects any data and then removes it again from the selection and again search with key press event the searchable data is not displayed, I can see that my axios call is working fine and I'm able to get the relevant data. but it is not displaying in dropdown as it says:
Error in render function: "TypeError: Cannot read property 'label' of null"
Which is coming from the company_name model which was selected. Following is my code in codepen
In this my axios is not working as it says mixed content:
https://codepen.io/anon/pen/Bdeqam?editors=1011' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://connect.stellar-ir.com/api/companies'. This request has been blocked; the content must be served over HTTPS.
So I'm unable to explain properly in this code set. But my code looks same as declared in codepen.
Help me out in this.
The error is because your computed values are undefined and undefined is not a string, so no string methods (toLowerCase()) are available. The response.data.model.data must look like this:
[
{
id: 1234,
name: 'example'
}, {
id: 12345,
name: 'example2'
}
]
if you get an object instead of an array push it to the array: this.serverData.push(response.data.model.data)
Replace your axios call with:
this.serverData = [
{
id: 1234,
name: 'example'
}, {
id: 12345,
name: 'example2'
}
]
to test it.
In your getOptions() method you calling loading(true or false), but your fetchIndexData() method has an asynchronous axios call. Use async/await, a callback function or a promise chain to wait for the data and show the loading indicator correctly.
On every keypress an request is send to the server i would recommend to use a debounce function.
Tipp
Line 42: https://stackoverflow.com/a/42028776/6429774
axios.post('http://connect.stellar-ir.com/api/companies', searchData).then(response => {
if(response.status === 200)
{
this.serverData = response.data.model.data
}
}).catch(error => {
console.log(error)
});

Component method response object data binding

I am starting to lose my mind in debugging an application that I inherited from a fellow developer who is absent.
I have narrowed down the problem to the following place in code (php files are checked, Vue instances are initialised, there are no syntax errors).
This is my the component that gets initialised:
var RadniStol = Vue.component('radnistol', {
template: '#template-RadniStol',
data() {
return {
tableData: [],
requestData: {
sort: "ID",
order: "DESC"
}
}
},
methods: {
reloadTable: function (event) {
data = this.requestData;
this.$http.post('php/get/radni_stol.php', data).then(response => {
console.log(response.data.bodyText);
this.tableData = response.data.records;
});
},
.
.
.
The PHP file that gets called with the POST method is working correctly, querying the database and echoing the response in a JSON format.
The thing that is making me pull out my hair is the following: the console.log(response.data) outputs the following into the console:
{"records":[{"DODAN_NA_RADNI_STOL":"1","..."}]}
It is an JSON object that I expected to have but when trying to assign it to the data of the component with:
this.tableData = response.data;
or any other way… response.data.records returns ‘undefined’ in the console. I have tryed with JSON.parse() but no success.
When logging types to console:
response variable is a response object with a status 200 and body and bodyText containing the data from the database.
response.data is a string type containing the string JSON with the data from the database.
When trying to use JSON.parse(response.data) or JSON.parse() on anything in the callback of the POST method I get the following error in the console:
RadniStol.js?version=0.1.1:17 Uncaught (in promise) SyntaxError: Unexpected token in JSON at position 0
at JSON.parse (<anonymous>)
at VueComponent.$http.post.then.response (RadniStol.js?version=0.1.1:17)
at <anonymous>
I am really starting to lose my mind over this issue, please help!
Thank you
If response.data is string, with JSON inside, then to access the records field, you should decode it like this:
JSON.parse(response.data).records
Not sure this has something to do with PHP or Vue.js, it is just plain javascript issue.
If it not decodes, than problem is definitely in response.data. For example
{"records":[{"DODAN_NA_RADNI_STOL":"1","..."}]}
is not a valid JSON, because key "..." needs to have some value.
But it seems to me that response.data is already parsed.
What I suggest you to do, is to write handler of the response as separate function, make response object that mimics actual response object by hand, and then test it separately from request. So you could show us request object and function that works with it.
I had the same error and fixed it.
Result will be response.body not response.data.
Here is my code:
getS: function(page) {
this.$http.get('vue-manager?page=' + page).then((response) => {
var data = JSON.parse(response.body);
this.student = data.data.data;
this.pagination = data.pagination;
});
},

debugging in Vue. Quick and dirty way to console.dir() a reactive variable?

I have this malfunctioning code within a Vue component that's caused by _errors being undefined in my data, at least when the page is loading.
data: function () {
var temp = {
show_debug : false
,password_changed_flag : false
,_errors : this.$store.state.form01._errors || {}
}
var data = Object.assign({}, this.$store.state.form01.data, temp);
//this is the part I am struggling with:
console.log("data:");
console.dir(data);
return data;
},
This isn't however about what I am doing wrong, it's about how to easily console.dir(data) Vue's reactive objects.
I.e. how can I print out a simple nested object, minus the getters and setters? And take a snapshot in time of that object.
i.e. _errors seems to be present now, but I'd like to only display the state of the object at the completion of the data function, not track subsequent changes.
What I am currently getting in Firefox and Chrome is instead the following:
console.log(JSON.parse(JSON.stringify(thing)))
Won't work on the Vue itself, but for data properties should be fine.
As of Vue3 it seems toRaw can serve that purpose as well.
Returns the raw, original object of a Vue-created proxy.
Yes, I had looked older issues too.
import {reactive, computed,ref, toRaw} from 'vue'
...
// this will be a reactive Vue object
const data_from_store = store.state[form_name].data;
console.dir({data_from_store});
// and this is an object I can pass as POST data or console.dir
const raw_data = toRaw(store.state[form_name].data);
console.dir({raw_data : raw_data});
console.dir from store/reactive:
Object { data_from_store: Proxy }
​
data_from_store: Proxy { <target>: {…}, <handler>: {…} }
​​
<target>: Object { run_option: "validate_only", rdbname: "HCM92ORP", fieldfilter_all: false, … }
​​
<handler>: Object { get: get(target, key, receiver), set: set(target, key, value, receiver), deleteProperty: deleteProperty(target, key)
, … }
​
console.dir after toRaw
Object { run_option: "validate_only", celery_task_id: null, rdbname: "HCM92ORP", fieldfilter_all: false, fieldfilter_keys: true, fieldfilter_lastupd: false, fieldfilter_effdt: true, fieldfilter_effstatus: false, fieldfilter_objectownerid: false, fieldfilter_descr: false, … }
​
celery_task_id: null
​
fieldfilter_all: false
...​
An image does a better job though: