I am currently exploring Angular2 in combination with TypeScript and I would like to include the Chartjs module in my application. In the chartjs documentation is shown how to do it using the common canvas html tag:
<canvas id="myChart" width="400" height="400"></canvas>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {[...]});
</script>
How can I do similar things with Angular2 and TypeScript?
Thanks in advance!
You can use npm module:
angular2-chartjs
Then you can use it like this in your module:
import { ChartModule } from 'angular2-chartjs';
#NgModule({
imports: [ ChartModule ]
// ...
})
export class AppModule {
}
And in html template:
<chart [type]="type" [data]="data" [options]="options"></chart>
Don't forget to fill it with data ;)
Something like:
#Component({
selector: 'my-component',
template: `
<canvas #myChart" width="400" height="400"></canvas>
<script>
`)}
export class MyComponent {
#ViewChild('myChart') myChart;
ngAfterViewInit() {
var myChart = new Chart(this.target.nativeElement, {[...]});
}
}
Related
I am running a Vue 3.0 with Quasar library. In the application there is a component that has a child component in it. With vue test utils v 2.2.6, I cannot seem to locate the child components in order to generate events. Why?
Simplified Parent Component
<template>
<q-dialog square persistent transition-show="scale" transition-hide="scale" >
<q-card-section class="q-px-xs q-pt-none">
<ChildComponent/>
</q-card-section>
</q-dialog>
</template>
<script setup>
//imports, props, etc
</script>
<style> ... </style>
Simplified Child Component
<template>
<q-card square bordered id="new-recipient-root-element" class="new-recipient">
<q-form>...</q-form>
</q-card>
</template>
<script setup>
//imports, props, etc
</script>
<style> ... </style>
Using Jest / vue test utils like so:
wrapper = mount(ParentComponent, {
props: { ...},
global: {
plugins: [i18n],
provide: {
store: ...
},
mocks: { ... }
}
});
wrapper.vm.show();
await nextTick();
domWrapper = new DOMWrapper(document.body);
...
await domWrapper.findComponent(ChildComponent).vm.$emit('myEvent');
domWrapper.findComponent(ChildComponent) always returns nothing. If I try domWrapper.findAllComponents(), it returns an empty array.
Also noticed that I can locate all the elements, but if I click on a button, no event seems to be generated since the handlers are not called and wrapper.emitted() contains nothing.
What am I missing?
I seem to do something wrong when I'm trying to target child components in nested router-views with click events.
Current situation:
I have a component one and component two. Both have a child component called dialog.
Component one and two are being loaded through a router-view in parent component dashboard. Each view has a button to show their child component "Modal".
The button seems to work fine on the view that gets loaded on pageload. But as soon as I switch routes the showModal function does not know the dialog element from which view to target.
I thought the components would be destroyed and rebuilt upon switching routes but apparently not.
Here is my code, I hope someone is able to help:
App
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
/**
* First we will load all of this project's JavaScript dependencies which
* include Vue and Vue Resource. This gives a great starting point for
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap')
/**
* Next, we will create a fresh Vue application instance and attach it to
* the body of the page. From here, you may begin adding components to
* the application, or feel free to tweak this setup for your needs.
*/
Vue.component('vuetest', require('./components/vuetest.vue'))
const Dashboard = require('./components/dashboard.vue')
const FirstRoute = require('./components/firstroute.vue')
const Second = require('./components/secondroute.vue')
const routes = [
{
path: '/dashboard',
component: Dashboard,
children: [
{
path: 'firstview',
name: 'firstview',
canReuse: false,
component: FirstRoute
},
{
path: 'secondview',
name: 'secondview',
canReuse: false,
component: Second
}
]
}
]
const router = new VueRouter({
routes // short for routes: routes
})
window.EventHub = new Vue()
const app = new Vue({
el: '#app',
router
});
Vuetest
<template>
<div>
<h1>Vue Test</h1>
<router-view></router-view>
</div>
</template>
<script>
export default {
created() {
},
mounted() {
console.log('Component ready.')
}
}
</script>
Dashboard Route
<template>
<div>
<h1>Dashboard</h1>
<navigation></navigation>
<router-view></router-view>
</div>
</template>
<script>
Vue.component('navigation', require('./navigation.vue'))
</script>
Navigation
<template>
<div>
<router-link :to="{ name: 'firstview' }">first</router-link>
<router-link :to="{ name: 'secondview' }">second</router-link>
</div>
</template>
First Route
<template>
<div class="firstroute">
<h1>First Route</h1>
<button class="showmodal" v-on:click="showModal">Showmodal</button>
<modal></modal>
</div>
</template>
<script>
export default {
methods: {
showModal: function () {
EventHub.$emit('showModal')
}
}
}
Vue.component('modal', require('./modal.vue'));
</script>
Second Route
<template>
<div class="secondroute">
<h1>Second Route</h1>
<button class="showmodal" v-on:click="showModal">Showmodal</button>
<modal></modal>
</div>
</template>
<script>
export default {
methods: {
showModal: function () {
EventHub.$emit('showModal')
}
}
}
Vue.component('modal', require('./modal.vue'));
</script>
Modal
<template>
<div class="dialog hidden">
Dialog
</div>
</template>
<style>
.hidden {
display: none;
}
</style>
<script>
export default{
created() {
EventHub.$on('showModal', this.showModal);
},
methods: {
showModal: function() {
document.querySelector('.dialog').classList.toggle('hidden');
}
}
}
</script>
I really appreciate any help.
tiny recomendations
':class' directive instead of native code:
document.querySelector('.dialog').classList.toggle('hidden');
components:
import Modal from './modal'
export default {
...
components:
Modal
}
...
}
instead of
Vue.component('modal', require('./modal.vue'));
.. also Vuex is a good point for this case
additional:
https://github.com/vuejs/vue-devtools
https://jsfiddle.net/uLaj738k/2/
As it turns out the problem was the moment I called the querySelector method.
Assigning the .dialog element to a const in mounted() solved my problem.
I have just started using angular2 and I am facing some situation to organize my logic. I am actually refactoring backend theme that consists of the two main components i.e login view that is supposed to appear on page load and main dashboard that will appear on successful login. I have no problem with the main dashboard template because i have refactored all the code its working fine. However the main problem is with the login module because dashboard consist of the sidebar, header and maincontent area. My real problem is that how do I exclude sidebar, header on loading the login page which will going to be the startpoint of my app. To be more precise, can i use the layout for the login module which is independent to the dashboard module? Here is my current code for the dashboard.
I would really appreciate if anyone could help me structure this app in proper way.
P.S I am using node as a backend
index.html
<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<base href="/">
<script src="systemjs.config.js"></script>
<script>
System.import('app/main').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<parent>
Loading...
</parent>
<!-- START SCRIPTS -->
<!-- START PLUGINS -->
</body>
</html>
app.component.ts
import { Component, NgZone } from '#angular/core';
import { HeaderComponent } from './header/header.component';
import { SidebarComponent } from './sidebar/sidebar.component';
import { AuthComponent } from './auth/auth.component';
import { ListComponent } from './blogs/list.component';
import {RouteConfig, ROUTER_DIRECTIVES, Router, AuxRoute} from '#angular/router-deprecated';
#Component({
selector: 'parent',
templateUrl:'app/main.html',
directives: [ROUTER_DIRECTIVES, HeaderComponent, SidebarComponent, AuthComponent]
})
#RouteConfig([
{ path: '/list', name: 'BlogList', component: ListComponent}
])
export class AppComponent {
constructor(private _router: Router , private _zone:NgZone){}
}
main.ts
import { bootstrap } from '#angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
import {ROUTER_PROVIDERS} from '#angular/router-deprecated';
bootstrap(AppComponent,[ROUTER_PROVIDERS]);
import {NgZone, enableProdMode} from '#angular/core'
main.html
<div class="page-container">
<div class="page-sidebar">
<mysidebar>
</mysidebar>
</div>
<div class="page-content">
<myheader>
</myheader>
<!-- PAGE CONTENT WRAPPER -->
<div class="page-content-wrap">
<router-outlet></router-outlet>
</div>
</div>
</div>
You can accomplish this by using a Service
export class AppComponentService {
public showSidebar : boolean = true;
public showHeader : boolean = true;
}
If you add this service during bootstrap:
bootstrap(AppComponent,[ROUTER_PROVIDERS, AppComponentService ]);
You can inject this into your AppComponent:
export class AppComponent {
constructor(
private _router: Router,
private _zone:NgZone,
private _appService: AppComponentService
){}
}
And change your template to:
<div class="page-container">
<div class="page-sidebar">
<mysidebar *ngIf="_appService.showSidebar">
</mysidebar>
</div>
<div class="page-content">
<myheader *ngIf="_appService.showHeader">
</myheader>
<!-- PAGE CONTENT WRAPPER -->
<div class="page-content-wrap">
<router-outlet></router-outlet>
</div>
</div>
</div>
Within your LoginComponent you can inject the same singleton service, and play with it on routerOnActivate and routerOnDeactivate:
export class LoginComponent {
constructor(private _appService: AppComponentService){}
routerOnActivate() : void {
this._appService.showSidebar = false;
this._appService.showHeader = false;
}
routerOnDeactivate() : void {
this._appService.showSidebar = true;
this._appService.showHeader = true;
}
}
I'm trying to wrap a WinJS rating control in an Angular2 component. When I debug, I can see that WinJS.UI.processAll(); is being called and executed. But I don't see the rating control.
How can I make it work?
Dashboard.cshtml:
#{
ViewBag.Title = "Dashboard";
}
<my-app></my-app>
<script src="/jspm_packages/system.js"></script>
<script src="/config.js"></script>
<script>
System.import('reflect-metadata')
.then(function () {
System.import('angular2')
.then(function () {
System.import("/js/app");
});
});
</script>
app.js:
import { Component, View, bootstrap } from 'angular2';
import 'reflect-metadata';
import 'winjs';
#Component({
selector: 'my-app'
})
#View({
template: '<div data-win-control=\'WinJS.UI.Rating\' data-win-options=\'{averageRating: 3.4}\'></div>'
})
class MyAppComponent {
constructor() {
}
onInit() {
WinJS.UI.processAll();
}
}
bootstrap(MyAppComponent);
As requested by #wonderfulworld
First of all, according to Adding the Windows Library for JavaScript to your page you must add the css file to your html.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/winjs/4.3.0/css/ui-light.min.css">
Second thing, from alpha37+ you must import and implement the lifecycle hook you're using, onInit in this case (see remove LifecycleEvent).
import { Component, View, bootstrap, OnInit} from 'angular2/angular2';
import 'reflect-metadata';
import 'winjs';
#Component({
selector: 'my-app'
})
#View({
template: '<div data-win-control=\'WinJS.UI.Rating\' data-win-options=\'{averageRating: 3.4}\'></div>'
})
class MyAppComponent implements OnInit {
onInit() {
WinJS.UI.processAll();
}
}
And that would be all. Here's the plnkr.
Glad it helped ;)
I’m working on an Angular 2 app and I have a component which inclundes a simple SVG rectangle, I’m trying to use Hammer.js library to be able to deplace and reform this SVG rectangle inside the view of my component,
therefore I’ve done those steps:
I’ve downloaded and copied 3 files to my project repository
hammer.js
hammer.min.js
hammer.min.map
I’ve added this script tag to my index head:
<script src="dev/jqueryLibs/hammer/hammer.js" type="text/javascript"></script>
And I get this error in the console:
Uncaught TypeError: Cannot read property 'addEventListener' of null
I’ve tried to import it in my component and add reference betwen the methode and the svg element, like this:
TS.File contents:
import {Component, ElementRef, AfterViewInit } from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {FORM_DIRECTIVES} from "angular2/common";
#Component({
selector: 'content',
templateUrl: 'content.component.html',
styleUrls: ['content.component.css'],
directives: [FORM_DIRECTIVES],
})
export class ContentComponent implements AfterViewInit{
static hammerInitialized = false;
constructor(private el:ElementRef)
{}
ngAfterViewInit() {
console.log('in ngAfterViewInit');
if (!ContentComponent.hammerInitialized) {
console.log('hammer not initialised');
var myElement = document.getElementById('test1');
var hammertime = new Hammer(myElement);
hammertime.on('swiperight', function(ev) {
console.log('caught swipe right');
console.log(ev);
});
ContentComponent.hammerInitialized = true;
} else {
console.log('hammer already initialised');
}
}
View file contents:
<svg class="simulation">
<rect id="test1" x="20" y="500" height="150" width="200" style="stroke:#EC9A20;stroke-width: 15; fill: none"/>
</svg>
Therefore I still am not able to move my SVG rectangle and it seems that Hammer.js is not even running according to this console message:
hammer not initialised
Anybody can tell me where is the error or what should I do?
This was resolved: The script tag of hammer declaration
must be placed after the jquery-ui library declaration in HTML file.
<script src="./dev/resources/js/jquery.js"></script>
<script src="./dev/resources/js/jquery-ui.js"></script>
<script src="./dev/jqueryLibs/jquery-1.12.1.min.js"></script>
<script src="./dev/jqueryLibs/jquery-migrate-1.2.1.min.js"></script>
<!--importer ici la js de bootstrap-->
<script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
<!--Importer ici hammer.js-->
<script src="dev/jqueryLibs/hammer/hammer.js" type="text/javascript"></script>