I'm not sure as to why the labels doesn't work but series works when fetching data from the database. I'm using vue and laravel.
Here is my code
<div id="chart">
<apexchart type="pie" width="380" :options="chartOptions" :series="series"></apexchart>
</div>
export default {
data: () => ({
employees: [],
series: [],
chartOptions: {
chart: {
width: 380,
type: 'pie',
},
labels: [],
responsive: [{
breakpoint: 80,
options: {
chart: {
width: 200
},
legend: {
position: 'bottom'
}
}
}]
}
}),
methods: {
kpiProgress () {
axios.get('/api/employee-kpi-progress', {
params: { employee_id: this.$store.state.authUser.employee_id }
})
.then(response => {
this.series = response.data
})
.catch(error => console.log(error))
},
kpaInfo () {
axios.get('/api/employee-kpa-info', {
params: { employee_id: this.$store.state.authUser.employee_id }
})
.then(response => {
this.chartOptions.labels = response.data
console.log(this.chartOptions.labels)
})
.catch(error => console.log(error))
},
}
}
Made it work. This is a really weird solution since this is my first time directly calling data from a response.
kpaInfo () {
axios.get('/api/employee-kpa-info', {
params: { employee_id: this.$store.state.authUser.employee_id }
})
.then(response => {
this.chartOptions = {
labels: response.data,
}
})
.catch(error => console.log(error))
},
Related
I have a line chart that gets data from the back end. I am able to plot the data but not the labels from the back end. This is my code:
import {Line} from 'vue-chartjs'
import axios from 'axios';
export default {
extends: Line,
props: ["data"],
methods: {
getScore() {
axios({
method: 'get',
url: 'http://localhost:5000/time',
}).then((response) => {
this.renderChart(
{
labels: [],
datasets: [
{
labels: response.data.score,
label: 'Stream',
backgroundColor: "#42c9d5",
data: response.data.score
}
]
},
{responsive: true, maintainApsectRatio: false}
)
})
.catch((error) => {
// eslint-disable-next-line
console.error(error);
});
}
},
mounted() {
this.getScore();
}
}
because I am getting the data from the getScore method. how Can I get the labels from another method? Or do I need to send two json responses? Also how do I loop through the json responses inside the this.renderchart?
I figured out how to do it. For those interested I passed a list of of dictionaries from the back end:
#app.route('/time')
def timeData():
response_object = {'status': 'success'}
SCORES = []
score = {}
score["value"] = [23,38,12]
score["date"] = ["Jan", "Feb", "Mar"]
SCORES.append(score)
response_object['score'] = SCORES
return jsonify(response_object)
I then added ... before the date key value pair:
import {Line} from 'vue-chartjs'
import axios from 'axios';
export default {
extends: Line,
props: ["data"],
methods: {
getScore() {
axios({
method: 'get',
url: 'http://localhost:5000/time',
}).then((response) => {
this.renderChart(
{
labels: [...response.data.score[0].date],
datasets: [
{
label: 'Stream',
backgroundColor: "#42c9d5",
data: response.data.score[0].value
}
]
},
{responsive: true, maintainApsectRatio: false}
)
})
.catch((error) => {
// eslint-disable-next-line
console.error(error);
});
}
},
mounted() {
this.getScore();
}
I have an API end point that returns an array of 24 values that I want to use in my chartjs within a vue component.
when the page loads I get no errors but the bars on the charts just don't show and I don't know why.
EDIT: I noticed that the async function returns a promise instead of the actual data:
async filterData() {
await this.$axios.get('/api/data_app/job_count_by_hour/')
.then(response => {
return this.chart_data = response.data;
})
}
here is the data return code, I have a function that populates the chart_data array :
data(){
return {
form:{
day: 'select day',
workspace:'',
machine_family: [],
duration: []
},
res: [],
total:[],
chart_data: [],
url: '/api/jobs/job_count_by_hour/',
days: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "sunday"],
barChart2: {
labels: ["6h", "7h", "8h", "9h","10h","11h", "12h", "13h", "14h", "15h", "16h", "17h", "18h", "19h", "20h", "21h","22h", "23h", "00h"],
datasets: [{
label: ["popularity"],
backgroundColor:"#f93232" ,
data: this.chart_data
},],
},
}
},
methods: {
async filterData() {
let _url = `${this.url}`
await this.$axios.get(_url)
.then(response => {
this.chart_data = response.data;
})
return this.chart_data
},
},
mounted() {
this.filterData()
}
}
this is the chart component:
<script>
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
in the parent component It looks like this:
en <BarChart :labels="barChart2.labels"
:datasets="barChart2.datasets"
:height="100"
>
</BarChart>ter code here
Turns out that when you try to update nested data, the component doesn't re-render.
This is how I solved it, I put the entire object in an update function and call that function when i get my data from the back end, I hope this helps!:
methods: {
onInput(value) {
this.filterData()
},
updateChart(data) {
this.datasets = [{
label: ["popularity"],
backgroundColor:"#f93232",
data: data
}]
},
async loadData() {
await this.$axios.get(this.url)
.then(response => {
this.updateChart(response.data)
})
},
},
mounted() {
this.loadData()
},
I am unit testing one of my components in an Aurelia project. I'd like to access my component's viewModel in my unit test but haven't had any luck so far.
I followed the example available at https://aurelia.io/docs/testing/components#manually-handling-lifecycle but I keep getting component.viewModel is undefined.
Here is the unit test:
describe.only('some basic tests', function() {
let component, user;
before(() => {
user = new User({ id: 100, first_name: "Bob", last_name: "Schmoe", email: 'joe#schmoe.com'});
user.save();
});
beforeEach( () => {
component = StageComponent
.withResources('modules/users/user')
.inView('<user></user>')
.boundTo( user );
});
it('check for ', () => {
return component.create(bootstrap)
.then(() => {
expect(2).to.equal(2);
return component.viewModel.activate({user: user});
});
});
it('can manually handle lifecycle', () => {
return component.manuallyHandleLifecycle().create(bootstrap)
.then(() => component.bind({user: user}))
.then(() => component.attached())
.then(() => component.unbind() )
.then(() => {
expect(component.viewModel.name).toBe(null);
return Promise.resolve(true);
});
});
afterEach( () => {
component.dispose();
});
});
Here is the error I get:
1) my aurelia tests
can manually handle lifecycle:
TypeError: Cannot read property 'name' of undefined
Here is the the line that defines the viewModel on the component object but only if aurelia.root.controllers.length is set. I am not sure how to set controllers in my aurelia code or if I need to do so at all.
I guess my question is:
How do I get access to a component's viewModel in my unit tests?
Edit #2:
I'd also like to point out that your own answer is essentially the same solution as the one I first proposed in the comments. It is the equivalent of directly instantiating your view model and not verifying whether the component is actually working.
Edit:
I tried this locally with a karma+webpack+mocha setup (as webpack is the popular choice nowadays) and there were a few caveats with getting this to work well. I'm not sure what the rest of your setup is, so I cannot tell you precisely where the error was (I could probably point this out if you told me more about your setup).
In any case, here's a working setup with karma+webpack+mocha that properly verifies the binding and rendering:
https://github.com/fkleuver/aurelia-karma-webpack-testing
The test code:
import './setup';
import { Greeter } from './../src/greeter';
import { bootstrap } from 'aurelia-bootstrapper';
import { StageComponent, ComponentTester } from 'aurelia-testing';
import { PLATFORM } from 'aurelia-framework';
import { assert } from 'chai';
describe('Greeter', () => {
let el: HTMLElement;
let tester: ComponentTester;
let sut: Greeter;
beforeEach(async () => {
tester = StageComponent
.withResources(PLATFORM.moduleName('greeter'))
.inView(`<greeter name.bind="name"></greeter>`)
.manuallyHandleLifecycle();
await tester.create(bootstrap);
el = <HTMLElement>tester.element;
sut = tester.viewModel;
});
it('binds correctly', async () => {
await tester.bind({ name: 'Bob' });
assert.equal(sut.name, 'Bob');
});
it('renders correctly', async () => {
await tester.bind({ name: 'Bob' });
await tester.attached();
assert.equal(el.innerText.trim(), 'Hello, Bob!');
});
});
greeter.html
<template>
Hello, ${name}!
</template>
greeter.ts
import { bindable } from 'aurelia-framework';
export class Greeter {
#bindable()
public name: string;
}
setup.ts
import 'aurelia-polyfills';
import 'aurelia-loader-webpack';
import { initialize } from 'aurelia-pal-browser';
initialize();
karma.conf.js
const { AureliaPlugin } = require('aurelia-webpack-plugin');
const { resolve } = require('path');
module.exports = function configure(config) {
const options = {
frameworks: ['source-map-support', 'mocha'],
files: ['test/**/*.ts'],
preprocessors: { ['test/**/*.ts']: ['webpack', 'sourcemap'] },
webpack: {
mode: 'development',
entry: { setup: './test/setup.ts' },
resolve: {
extensions: ['.ts', '.js'],
modules: [
resolve(__dirname, 'src'),
resolve(__dirname, 'node_modules')
]
},
devtool: 'inline-source-map',
module: {
rules: [{
test: /\.html$/i,
loader: 'html-loader'
}, {
test: /\.ts$/i,
loader: 'ts-loader',
exclude: /node_modules/
}]
},
plugins: [new AureliaPlugin()]
},
singleRun: false,
colors: true,
logLevel: config.browsers && config.browsers[0] === 'ChromeDebugging' ? config.LOG_DEBUG : config.LOG_INFO, // for troubleshooting mode
mime: { 'text/x-typescript': ['ts'] },
webpackMiddleware: { stats: 'errors-only' },
reporters: ['mocha'],
browsers: config.browsers || ['ChromeHeadless'],
customLaunchers: {
ChromeDebugging: {
base: 'Chrome',
flags: [ '--remote-debugging-port=9333' ]
}
}
};
config.set(options);
};
tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"importHelpers": true,
"lib": ["es2018", "dom"],
"module": "esnext",
"moduleResolution": "node",
"sourceMap": true,
"target": "es2018"
},
"include": ["src"]
}
package.json
{
"scripts": {
"test": "karma start --browsers=ChromeHeadless"
},
"dependencies": {
"aurelia-bootstrapper": "^2.3.0",
"aurelia-loader-webpack": "^2.2.1"
},
"devDependencies": {
"#types/chai": "^4.1.6",
"#types/mocha": "^5.2.5",
"#types/node": "^10.12.0",
"aurelia-testing": "^1.0.0",
"aurelia-webpack-plugin": "^3.0.0",
"chai": "^4.2.0",
"html-loader": "^0.5.5",
"karma": "^3.1.1",
"karma-chrome-launcher": "^2.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-source-map-support": "^1.3.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^3.0.5",
"mocha": "^5.2.0",
"path": "^0.12.7",
"ts-loader": "^5.2.2",
"typescript": "^3.1.3",
"webpack": "^4.23.1",
"webpack-dev-server": "^3.1.10"
}
}
Original answer
If you're manually doing the lifecycle, you need to pass in a ViewModel yourself that it can bind to :)
I don't remember exactly what's strictly speaking needed so I'm quite sure there's some redundancy (e.g. one of the two bindingContexts passed in shouldn't be necessary). But this is the general idea:
const view = "<div>${msg}</div>";
const bindingContext = { msg: "foo" };
StageComponent
.withResources(resources/*optional*/)
.inView(view)
.boundTo(bindingContext)
.manuallyHandleLifecycle()
.create(bootstrap)
.then(component => {
component.bind(bindingContext);
}
.then(component => {
component.attached();
}
.then(component => {
expect(component.host.textContent).toEqual("foo");
}
.then(component => {
bindingContext.msg = "bar";
}
.then(component => {
expect(component.host.textContent).toEqual("bar");
};
Needless to say, since you create the view model yourself (the variable bindingContext in this example), you can simply access the variable you declared.
In order to get it to work, I had to use Container:
import { UserCard } from '../../src/modules/users/user-card';
import { Container } from 'aurelia-dependency-injection';
describe.only('some basic tests', function() {
let component, user;
before(() => {
user = new User({ id: 100, first_name: "Bob", last_name: "Schmoe", email: 'joe#schmoe.com'});
user.save();
});
beforeEach(() => {
container = new Container();
userCard = container.get( UserCard );
component = StageComponent
.withResources('modules/users/user-card')
.inView('<user-card></user-card>')
.boundTo( user );
});
it('check for ', () => {
return component.create(bootstrap)
.then(() => {
expect(2).to.equal(2);
return userCard.activate({user: user});
});
});
});
When I call a mutation on my client I get the following warning:
writeToStore.js:111 Missing field updateLocale in {}
This is my stateLink:
const stateLink = withClientState({
cache,
resolvers: {
Mutation: {
updateLocale: (root, { locale }, context) => {
context.cache.writeData({
data: {
language: {
__typename: 'Language',
locale,
},
},
});
},
},
},
defaults: {
language: {
__typename: 'Language',
locale: 'nl',
},
},
});
And this is my component:
export default graphql(gql`
mutation updateLocale($locale: String) {
updateLocale(locale: $locale) #client
}
`, {
props: ({ mutate }) => ({
updateLocale: locale => mutate({
variables: { locale },
}),
}),
})(LanguagePicker);
What am I missing?
I was getting the same warning and solved it by returning the data from the mutation method.
updateLocale: (root, { locale }, context) => {
const data = {
language: {
__typename: 'Language',
locale,
}
};
context.cache.writeData({ data });
return data;
};
At the moment, apollo-link-state requires you to return any result. It can be null too. This might be changed in the future.
I need a way to unit test the "edit" function in the code below. It is different form the other questions because my function returns no value.
class QslTable extends React.PureComponent {
this.state = {
data: [{
key: '0',
callSign: {
editable: true,
value: 'F1ABD',
},
QSODate: {
editable: true,
value: '10-05-31',
},
band: {
editable: true,
value: '32',
},
mode: {
editable: true,
value: 'Phone',
},
dxccEntity: {
editable: true,
value: 'France',
},
delete: {
editable: false,
value: 'Delete',
},
}],
};
edit(index) {
const { data } = this.state;
Object.keys(data[index]).forEach((item) => {
if (data[index][item] && typeof data[index][item].editable !== 'undefined') {
data[index][item].editable = true;
}
});
this.setState({ data });
}
}
This doesn't work:
it('should render the component', () => {
const renderedComponent = shallow(<QslTable />);
expect(renderedComponent.find('edit')).toBeDefined();
});
The function doesn't return any value. I have no clue how to test the function. I have looked at the documentation for Jest, but couldn't figure it out. Any help would be appreciated!