VueJS2: Help tracking down "TypeError: Cannot read property 'XXX' of undefined" - vuejs2

I am using VueJS2 and having the following issue when returning API data from a function:
Uncaught (in promise) TypeError: Cannot read property 'P_shortName' of undefined
While the UI does render the data successfully after a while, I get annoying console log output above.
In template I have:
<td>
{{ registerName(country.registerIdentifier_FK) }}
</td>
And the registerName() looks like so:
methods: {
async registerName(id) {
const register = this.registers.find(
register => id === register.registerIdentifier_PK
)
return register.P_shortName
},
}
What can I do to mitigate this error?

Try it.
And I didn't see the need to use async here.
registerName(id) {
const register = this.registers.find(
(register) => id === register.registerIdentifier_PK
);
return register ? register.P_shortName : null;
}

Related

Vue.js error: Cannot read property 'filter' of undefined

Im building an app to consume a json and list it with a search filter input and other stuffs
I've already tried to create the function but didnt work
{
produtoFiltrado:function()
{
var self=this;
return this.produtos.filter(function(cust){
return cust.nome.toLowerCase().indexOf(self.search.toLowerCase())>=0;
});
}
}
Its showing this error: Cannot read property 'filter' of undefined
Here is the codesandbox url:
https://codesandbox.io/s/vue-template-7iev3?fontsize=14
I've fixed with the declaration of array
produtos: [ { all-stuffs-here } ]
The brackets were missing
But now its showing this error:
Cannot read property 'search' of undefined

Pouchdb query() leaving out documents on emit()

For some reason my filter is not working correctly. It was working fine a moment ago and then for some reason it stopped returning all of the templates and only started returning one of them.
Why might it be returning it twice but only giving me one?
I have the following code:
export async function testMe() {
const company_id = await AsyncStorage.getItem('company_id');
const device_db = new PouchDB(company_id, {});
device_db.query(function(doc, emit){
console.log(doc.type, doc._id, doc._rev);
if(doc.type == 'template') {
emit(doc._id, doc);
}
}).then((result) => {
console.log("Returned", result);
})
}
What is unexpectedly happening is this is what gets returned:
template template_1 18-5918af4c5370d9755d0bb8b6dcb21ea1
template template_2 19-8191dec49dfa8c1a2f03d752a193f09e
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
undefined "dpbcab6843-2cdf-4d4c-87ae-286dcddaac22" "2-8f03f3127771dadd3c8f7beb3e827982"
undefined "dpdc6f6cd0-6c6d-4974-a166-b848a0217af4" "2-0eec1a8d925641aa8bf30e058e6515e7"
undefined "dpe1573a70-a281-4e15-a997-82d8bf8fabfa" "2-d3bbcb81344f61cc94459610695c6670"
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
You can ignore the undefined, but what I am trying to show is look at what gets returned twice:
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
In the Returned console.log(), this is the only thing that gets returned (the last template_3 piece of data, totally ignoring the other templates even though they are both type template):
{"total_rows":6,"offset":0,"rows":[{"key":"template_3","id":"template_3","value":{..}}]}
Edit
It's getting even weirder. I just opened template_2 and did a save (in Cloudant) and synced it with my device to update the _rev and now I get:
template template_1 18-5918af4c5370d9755d0bb8b6dcb21ea1
template template_2 20-c549fe868735ef0099b80f6668af611c
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
undefined "dpbcab6843-2cdf-4d4c-87ae-286dcddaac22" "2-8f03f3127771dadd3c8f7beb3e827982"
undefined "dpdc6f6cd0-6c6d-4974-a166-b848a0217af4" "2-0eec1a8d925641aa8bf30e058e6515e7"
undefined "dpe1573a70-a281-4e15-a997-82d8bf8fabfa" "2-d3bbcb81344f61cc94459610695c6670"
template template_3 39-74f3b82ce4a38a501810b5ff31efc593
template template_2 20-c549fe868735ef0099b80f6668af611c
Which returns (leaving out template_3):
{"total_rows":6,"offset":0,"rows":[{"key":"template_2","id":"template_2","value":{..}}]}
Edit 2
I added:
.catch((err) => {
console.log(err);
})
And get this: {"status":409,"name":"conflict","message":"Document update conflict","error":true}
However, I do the following an all _conflict arrays are empty:
device_db.allDocs({conflicts: true})
.then((data) => {
for (let d of data.rows) {
console.log(d.doc._conflicts);
}
});
I believe temporary queries like this should have a key, otherwise the query would not know what documents you want to select. The example from the PouchDb docs is
db.query(function (doc, emit) {
emit(doc.name);
}, {key: 'foo'}).then(function (result) {
// found docs with name === 'foo'
}).catch(function (err) {
// handle any errors
});
so that documents with a "name" field equal to "foo" are returned by the query. In your query the key appears to be undefined. This might explain the odd results you are getting?

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)
});

Error handling with Angular2 async pipe

I am using the Angular2 async pipe to stream values into the DOM. Here's a real simple example:
const stream = Observable.interval(1000)
.take(5)
.map(n => { if (n === 3) throw "ERROR"; return n; });
<div *ngFor="for num of stream | async">
{{num}}
</div>
<div id="error"></div>
What I would like to do is to have the sequence of 1-5 displayed, but on the error item (3), somehow populate the #error div with the error message.
This seems to require two things: first is the ability of the Angular async pipe to do something intelligent with errors, which I see no sign of. Looking at the source code, apparently it throws a JS exception, which doesn't seem too friendly.
Second is the ability to restart or continue the sequence after the error. I have read about catch and onErrorResumeNext and so on, but they all involve another sequence which will be switched to on an error. This greatly complicates the logic of generating the stream, on which I would just like to put a series of numbers (in this simple example). I have the sinking feeling that once an error occurs the game is over and the observable is completed and can only be "restarted" with a different observable. I'm still learning observables; is this in fact the case?
So my question is twofold:
Can Angular2's async pipe do something intelligent with errors?
Do observables have some simple way to continue after an error?
Yes you're right regarding the catch operator and the ability to do something after errors occur...
I would leverage the catch operator to catch the error and do something:
const stream = Observable.interval(1000)
.take(5)
.map(n => {
if (n === 3) {
throw Observable.throw(n);
}
return n;
})
.catch(err => {
this.error = error;
(...)
});
and in the template:
<div>{{error}}</div>
To be able to go on the initial observable, you need to create a new one starting at the point where the error occurs:
createObservable(i) {
return Observable.interval(1000)
.range(i + 1, 5 - i)
.take(5 - i)
});
}
and use it in the catch callback:
.catch(err => {
this.error = error;
return this.createObservable(err);
});
These two questions could help you:
How to resumeOnError (or similar) in RxJS5
RxJS Continue Listening After Ajax Error (last answer)
1) no, The async pipe subscribes and unsubscribes and returns the events it receives. You would need to handle the errors before they receive the async pipe.
2) You can use the catch operator and when it returns an observable then its value(s) is emitted by the .catch(err => Observable.of(-1)) instead of the error.
You could use this to emit a special "error" value and then use something like *ngIf="num === -1 to show the error value in some special way.
You can find more information on this https://blog.thoughtram.io/angular/2017/02/27/three-things-you-didnt-know-about-the-async-pipe.html
#Thierry Templier answer was correct but is now a bit outdated. Here's how to do it with the latest RXJS.
this.myObservable$ = this.myService.myFunc().pipe(
catchError(() => of([])) // this will emit [] if the request fails - u could handle this [] emit on error in the service itself
)
then HTML as normal:
<div *ngFor="let xxx of (myObservable$ | async)">
</div>
Note $ at end of Observable name is Angular recommended way to denote an Observable.
I was facing a similar issue and came up with another approach. I do not know if it's a good way of doing it, but it works.
template where you want to show the result of your observable:
<div *ngIf="tableData$ | async as tableData; else loader" class="mt-4">
<!-- do something with tableData -->
</div>
<ng-template #loader>
<loading [target]="tableData$"></loading>
</ng-template>
The loading component:
export class LoadingComponent implements OnInit {
private _errorMessageSubject : Subject<string> = new Subject<string>();
private _errorMessage$ : Observable<string> = this._errorMessageSubject.asObservable();
public get errorMessage$() : Observable<string> { return this._errorMessage$; }
private _target : Observable<any> | null = null;
public get target() : Observable<any> | null { return this._target }
// this input does nothing except catch the error and feed the
// message into the errorMessage subject.
#Input() public set target(o: Observable<any> | null) {
if(o == null) { return; }
this._target = o.pipe(
catchError((error, _) => {
this._errorMessageSubject.next(error);
return of(null);
}),
);
};
constructor() { }
ngOnInit(): void {
}
}
loader template:
<div *ngIf="target && target | async;">
</div>
<div *ngIf="errorMessage$ | async as error; else loading">
<p class="text-danger">{{ error }}</p>
</div>
<ng-template #loading> <!-- simply a spinner icon -->
<div class="d-flex justify-content-center">
<fa-icon [icon]="['fas', 'spinner']" size="6x" [spin]="true"></fa-icon>
</div>
</ng-template>
I am not perfectly sure if its a good approach to subscribe to the observable twice, as subscribing is done in the original component that needs the data and in the loader, but otherwise this seems to work properly.

Redux Async Test with Webpack+karma+etc

I was trying to do a async action test but failed miserable :(
the test in question is this one: https://github.com/persocon/destiny-weekly/blob/test/test/actions/index.spec.jsx
I'm getting this error message:
1) fill in GET_OPTIONS when fetching all options is done
Async Actions
undefined is not an object (evaluating 'store.dispatch(actions.getOptions()).then')
/Users/persocon/Projects/destiny-weekly/test/test.bundle.js:14669:42 <- webpack:///test/actions/index.spec.jsx:49:7
and I have no clue what that means, if this was to help I'm more confuse then ever.
UPDATE
had to implement fetch on the action itself instead of the $.get I was using but now I get a new error pointing to my action :v even it working on the browser:
1) fill in GET_OPTIONS when fetching all options is done
Async Actions
Can't find variable: fetch
/Users/persocon/Projects/destiny-weekly/test/test.bundle.js:42473:9 <- webpack:///src/app/javascript/actions/index.jsx:32:9
/Users/persocon/Projects/destiny-weekly/test/test.bundle.js:15691:23 <- webpack:///~/redux-thunk/lib/index.js:12:0
/Users/persocon/Projects/destiny-weekly/test/test.bundle.js:14669:20 <- webpack:///test/actions/index.spec.jsx:48:19
UPDATE 2
Action code:
const setOptions = (result) => {
return {
type: 'GET_OPTIONS',
options: result
}
}
const getOptions = () => {
return dispatch => {
dispatch(startLoading())
return fetch('/api/selectActivity')
.then(response => response.json())
.then( json => {
dispatch(doneLoading());
json.unshift({advisorTypeCategory: "Selecione Uma Atividade", identifier: "", disabled: "disabled"});
dispatch(setOptions(json));
}
)
}
}
Ya, the Async Action Creators Example is using 'fetch' which is a bit contrived, but should work in theory. One simple solution might be to implement it with this isomorphic fetch library. Good luck!
The solution was to implement the Isomorphic Fetch
Because as 4m1r told it was a contrived function and couldn't be found.