I'm struggling with an error. It tooks me over 2 days and still no solution...
I'm using Ionic2 as a frontend and Horizon with RethinkDB as a backend. I have a table called 'messages' and few messages in it. I just want to get all these messages and show them on my HomePage.
Here is my code:
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
declare var Horizon;
#Component({
templateUrl: 'build/pages/home/home.html'
})
export class HomePage {
test: any[];
constructor(public navCtrl: NavController) {
}
getMessages(){
let test = [];
let hz = new Horizon({host: 'localhost:3100'});
hz.connect();
let messages = hz('messages');
messages.watch().subscribe(messages => {
for(let i = 0; i<messages.length; i++){
console.log(messages[i].text);
console.log(messages[i].id);
this.test.push([{
text: messages[i].text,
id: messages[i].id
}])
}
});
}
}
I tried with many combinations of this.test.push but still no luck. I'm doing something wrong... Hope you guys help me!
The answer to this problem was just ensuring to reference the variable you think you're referencing.
this.test is undefined. Instead of let test = []; you should change it to this.test = [];.
Or you can change this.test.push(... to test.push(... and it should also work fine.
Being cautious when using this and juggling scope in Javascript is one of the trickiest parts of the language. I wish there was some indicator in the error as to what part in the chain is actually undefined as you thought .push was undefined on this.test where actually it was test which was undefined on the this object.
Related
I have a basic expo app with React Navigation.
In the top function Navigation I am initiating a useMutation call to an Apollo server like so:
import { callToServer, useMutation } from '../graphQL';
function Navigation() {
console.log("RENDERED");
const [call] = useMutation(callToServer);
call({ variables: { uid: 'xyz', phoneNumber: '123' } });
...
And my GraphQL settings is as follows:
import {
ApolloClient,
createHttpLink,
InMemoryCache,
useMutation,
} from '#apollo/client';
import { onError } from '#apollo/client/link/error';
import { callToServer } from './authAPI';
const cache = new InMemoryCache();
const httpLink = createHttpLink({
uri: `XXXXXXX/my-app/us-central1/graphql`,
});
const errorLink = onError(({ graphQLErrors, networkError }) => {
...
});
const client = new ApolloClient({
cache,
link: errorLink.concat(httpLink),
});
export {
useMutation,
callToServer,
};
export default client;
I want to clarify that I removed the httpLink from the client setting and I still get the two renders per call. I can see in the console that console.log("RENDERED") prints three times. Once when the app loads (normal) and twice after the useMutation call (not normal?)
What's going on here? Why is react re-renders twice per useMutation call? How do I avoid it?
UPDATE
I did further digging and it seems that useMutation does indeed cause the App to render twice - once when the request is sent, and once when it receives a response. I'm not sure I'm loving this default behavior which seems to have no way to disable. Why not let us decide if we want to re-render the App?
If someone has more insight to offer, Id love to hear about it.
Probably it's too late and maybe you've already found the solution, but still...
As I see you do not need data returned from mutation in the code above. In this case you can use useMutation option "ignoreResults" and set it to "true". So mutation will not update "data" property and will not cause any render.
I'm trying to test a component that uses vuex inside it, I'm trying to pass the store of the respective component so that it can be assembled, but I'm getting the following error:
_vuex.default.store is not a constructor
I have no idea what's going on and I couldn't find anything on the internet to help me, if anyone can help me, I would be very grateful!
Spec file
import {shallowMount,createLocalVue} from '#vue/test-utils'
import Vuex from 'vuex'
import sateliteComponent from '#/components/satelite/listaSatelite.vue'
import sateliteStore from '#/core/modules/satelite/index.js'
var vueWithVuex = createLocalVue()
vueWithVuex.use(Vuex)
const store = new Vuex.store({
sateliteStore
})
describe('testes componente satelite', () => {
test('instanciado', () => {
const wrapper = shallowMount(sateliteComponent,{
localVue:vueWithVuex,
store
})
expect(wrapper.isVueInstance()).toBeTruthy()
});
});
if necessary, I can post my component that is being rendered
Correct with this:
const store = new Vuex.Store({
sateliteStore
})
It should be Vuex.Store check the capitalization of the word store.
For anyone else visiting:
Even with the right casing, this error can also come up if you try to use
new Vuex.Store()
before running
Vue.use(Vuex)
We are using the aurelia component testing as defined here (with jest): https://aurelia.io/docs/testing/components#testing-a-custom-element
The component we are testing has a transient dependency. We are creating a mock for this dependency but when we run the tests using au jest, the real one always gets injected by the DI container and never the mock.
Here is the Transient service:
import { transient } from "aurelia-framework";
#transient()
export class ItemService {
constructor() {
}
getItems(): void {
console.log('real item service');
}
}
Here is the 'Mock' service (we have also tried using jest mocks but we get the same result):
import { transient } from "aurelia-dependency-injection";
#transient()
export class MockItemService{
getItems():void {
console.log('mock item service');
}
}
Here is the component under test:
import {ItemService} from "../services/item-service";
import { autoinject } from "aurelia-dependency-injection";
#autoinject()
export class TestElement {
constructor(private _itemService: ItemService) {
}
attached(): void {
this._itemService.getItems();
}
}
Here is the spec file:
import {TestElement} from "../../src/resources/elements/test-element";
import {ComponentTester, StageComponent} from "aurelia-testing";
import {ItemService} from "../../src/resources/services/item-service";
import {MockItemService} from "./mock-item-service";
import {bootstrap} from "aurelia-bootstrapper";
describe('test element', () => {
let testElement;
const path: string = '../../src/resources/elements/test-element';
beforeEach(() => {
testElement = StageComponent.withResources(path).inView(`<test-element></test-element>`);
testElement.bootstrap(aurelia => {
aurelia.use.standardConfiguration();
aurelia.container.registerTransient(ItemService, MockItemService);
});
});
afterEach(() => {
testElement.dispose();
});
it('should call mock item service', async() => {
await testElement.create(bootstrap);
expect(testElement).toBeTruthy();
})
});
But every-time the test is run, the console logs out the real service and not the mock. I have traced this to the aurelia-dependency-injection.js in the Container.prototype.get function. The issue seems to be around this section of code:
var registration = aureliaMetadata.metadata.get(aureliaMetadata.metadata.registration, key);
if (registration === undefined) {
return this.parent._get(key);
}
The registration object seems to be a bit odd, if it was undefined, the code would work as the correct dependency is registered on the parent and it would get the mock dependency. However, it is not undefined therefore it registers the real service in the DI container on this line:
return registration.registerResolver(this, key, key).get(this, key);
The registration object looks like this:
registration = TransientRegistration {_key = undefined}
Is this a bug in aurelia or is there something wrong with what I am doing?
Many Thanks
p.s. GitHub repo here to replicate the issue: https://github.com/Magrangs/aurelia-transient-dependency-issue
p.p.s Forked the DI container repo and added a quick fix which would fix my particular issue but not sure what the knock on effects would be. If a member of the aurelia team could check, that would be good:
https://github.com/Magrangs/dependency-injection/commit/56c7d96a496e76f330a1fc3f9c4d62700b9ed596
After talking to Rob Eisenberg on the issue there is a workaround for this problem. Firstly remove the #transient decorator on the class and then in your app start (usually main.ts) register the class there as a transient.
See the thread here:
https://github.com/Magrangs/dependency-injection/commit/56c7d96a496e76f330a1fc3f9c4d62700b9ed596
I have also updated the repo posted above: https://github.com/Magrangs/aurelia-transient-dependency-issue
to include the fix.
Hopefully this will help any other devs facing the same issue.
I'm using a custom test helper which requires access to the Ember data store, but I don't know how to access it from the given application argument.
export default registerAsyncHelper('myCustomHelper', function(app) {
console.log(app); // how to access store?
let store = app.__registry__.registrations['service:store'];
store.pushPayload(// json payload);
});
How can I get access to the store when registering a custom helper? I've been trying to figure out a way to access it from the __registry__.registrations['service:store'] key but that gives me an undefined value, when I can see that it's there and has the pushPayload function. Help would be greatly appreciated
Hah! I think I got it:
export default registerAsyncHelper('myCustomHelper', function(app) {
let instance = app.buildInstance();
let store = instance.lookup('service:store');
store.pushPayload(// json payload);
});
Not sure if that has any side effects though? Please let me know if it does, I think I've spent enough time trying to setup a good test environment already :p
This is typescript, but it should hopefully work the same in js (without the type annonations though)
// tests/helpers/get-service.ts
import { getContext } from "#ember/test-helpers";
export function getService<T>(name: string): T {
const { owner } = getContext();
const service = owner.lookup(`service:${name}`);
return service;
}
example usage:
// tests/helpers/create-current-user.ts
import { run } from '#ember/runloop';
import { DS } from 'ember-data';
import Identity from 'emberclear/data/models/identity/model';
import { getService } from './get-service';
export async function createCurrentUser(): Promise<Identity> {
const store = getService<DS.Store>('store');
const record = store.createRecord('identity', {
id: 'me', name: 'Test User'
});
await record.save();
return record;
}
this code is from https://emberclear.io
https://gitlab.com/NullVoxPopuli/emberclear/tree/master/packages/frontend/tests/helpers
hope this helps :)
I have an Ionic 2 Component. It renders a html page. In the constructor, it fetches data in a promise. The html uses the data (personModel) and displays the values.
My problem is the html wants to render before the promise has completed getting the data, resulting in an error.
TypeError: self.context.personModel is undefined
How do I make sure the html waits for the data to load before it tries to render?
Thanks
html
<h2>{{personModel.firstName}} {{personModel.lastName}}</h2>
ts
#Component({
templateUrl: 'build/pages/person/person.html',
})
constructor() {
// promise that loads data
this.utilityService.getLoggedInPerson().then((data: string) => {
this.personModel = JSON.parse(data);
}
}
personModel: any[];
constructor() {
this.personModel = [];
// your call
}
Try to initialize the object.
EDIT: answered together :P
If your service can return an Observable, the async pipe might help.
https://angular.io/docs/ts/latest/guide/pipes.html
You need to define the member variable straight away, and then assign the data to it, i.e:
personModel: any;
constructor() {
// promise that loads data
this.utilityService.getLoggedInPerson().then((data: string) => {
this.personModel = JSON.parse(data);
}
}