I'm trying to make a global click event directive. But document:click does not work for me.
import 'package:angular/angular.dart';
#Directive(
selector: '[clickOutside]'
)
class ClickOutsideDirective {
#HostListener('click', [r'$event.target'])
void onClick(targetElement){
print('Target:' + targetElement.toString());
}
}
When changing document:click to click I get expected behavior. But of course not globally. What am I doing wrong?
The document: and similar event scopes were removed in Dart.
Use instead
import 'dart:html';
class ClickOutsideDirective implements OnInit, OnDestroy {
StreamSubscription _docClickSub;
ngOnInit() {
_docClickSub = document.onClick.listen((event) {
print('Target:' + event.target.toString());
});
}
ngOnDestroy() {
_docClickSub?.cancel();
_docClickSub = null;
}
}
Related
I created a simple LitElement with CodeMirror6 I can see the Editor, but when I call the same LitElement in Vaadin , the styling is completely gone.
I have tried both 14 and 23. Same issue.
CodeMirror6 Lit
import { LitElement, html } from 'lit';
import { EditorState, EditorView, basicSetup } from "#codemirror/basic-setup"
import { sql } from '#codemirror/lang-sql';
import { oneDark } from '#codemirror/theme-one-dark';
export class App extends LitElement {
static get properties() {
return {
value: String,
};
}
render() {
return html`
<div id="codeeditor"></div>`;
}
firstUpdated() {
let editorState = EditorState.create({
doc: this.value, extensions: [
basicSetup,
oneDark,
sql(),
]
});
var element = document.getElementById('codeeditor');
const editor = new EditorView(
{
state: editorState,
parent: element
}
);
}
createRenderRoot() {
return this;
}
}
customElements.define('code-mirror', App);
LitElement Code Editor Image - https://i.stack.imgur.com/0MsjU.png
No issue here works perfectly, but When I call the above litelement into Vaadin . The formatting and styling is completely gone.
LitElement in Vaadin Image : https://i.stack.imgur.com/RP35C.png
Any suggestion or pointer for me to fix this issue.
The problem is way on which vaadin renders child components in a Vertical|Horizontal layout (shadowRoot with slots).
If you add your implementation to the ROOT content (first layout), the codemirror will work fine as the styles will be applied correctly.
I tried extending new module about #CssImport with codemirror styles. The module was displaying correctly but the codemirror events stopped working because of the vaadin structure ;/
The problem can be worked around as follows. I know it's not elegant, but it works.
Create a new element in document.body
Init codemirror in the new element
Move codemirror from created element to element rendered by module
import {EditorState, EditorView, basicSetup} from "#codemirror/basic-setup"
import {sql} from "#codemirror/lang-sql"
import {html, LitElement} from "lit";
import { oneDark } from '#codemirror/theme-one-dark';
export class App extends LitElement {
static get properties() {
return {
value: String,
};
}
createRenderRoot() {
return this;
}
render() {
return html`<span id="codeeditor"></span>`;
}
firstUpdated() {
var element = document.getElementById('codeeditor');
var parent = document.createElement("div");
document.body.append(parent);
new EditorView({
state: EditorState.create({
extensions: [basicSetup, oneDark ,sql()]
}),
parent: parent
})
document.body.removeChild(parent);
element.appendChild(parent);
}
}
customElements.define('code-mirror', App);
I am trying to call server side function from client using littemplate. I have checked examples on Vaadin site and found that client may call server side via this.$server._some_method.
I tried to use $server in littemplate but during frontend compilation vaadin throws error stating that "Property '$server' does not exist on type 'HelloWorld'."
Please let me know what is wrong with this program and guide me.
Thank you.
Littemplate
import {LitElement, html} from 'lit-element';
import '#vaadin/vaadin-button/vaadin-button.js';
class HelloWorld extends LitElement {
render() {
return html`
<div>
<vaadin-button id="helloButton">Click me!</vaadin-button>
</div>`;
}
sayHello(){
showNotification("Hello");
this.$server.greet(); //Problematic statement.
}
}
customElements.define('hello-world', HelloWorld);
Java
package com.example.application.littemplate;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.littemplate.LitTemplate;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.template.Id;
import com.vaadin.flow.component.textfield.TextField;
//HelloWorld.java
#Tag("hello-world")
#JsModule("./views/littemplate/hello-world.ts")
public class HelloWorld extends LitTemplate {
#Id
// Uses the vaadin-button id "helloButton"
private Button helloButton;
public HelloWorld() {
helloButton.addClickListener(event -> Notification.show("Hello " + nameField.getValue()));
}
#ClientCallable
public void greet() {
System.out.println("Hello server");
}
}
Typescript does not know that LitTemplate has a $server variable. You have to define it yourself.
You can use type any or define your interface.
For example:
private $server?: MyTestComponentServerInterface;
And add the #ClientCallable functions:
interface MyTestComponentServerInterface {
greet(): void;
}
In your case, your typescript could be:
import {LitElement, html} from 'lit-element';
import '#vaadin/vaadin-button/vaadin-button.js';
class HelloWorld extends LitElement {
private $server?: HelloWorldServerInterface;
render() {
return html`
<div>
<vaadin-button id="helloButton">Click me!</vaadin-button>
</div>`;
}
sayHello(){
showNotification("Hello");
this.$server!.greet(); // should work with autocompletion
}
}
interface HelloWorldServerInterface {
greet(): void;
}
customElements.define('hello-world', HelloWorld);
I can't figure out how to pass my app object to my TypeGrapQL resolvers.
I created my types and resolvers and setup a graphql server using express-graphql. I was able to run the graph, but no luck in passing the app object to use the registered services.
My graphql.service.ts looks like this:
import { ServiceAddons } from '#feathersjs/feathers'
import { graphqlHTTP } from 'express-graphql'
import 'reflect-metadata'
import { buildSchemaSync } from 'type-graphql'
import { Container } from 'typedi'
import { Application } from '../../declarations'
import { Graphql } from './graphql.class'
import { ArticleResolver } from './resolvers/article.resolver'
// Add this service to the service type index
declare module '../../declarations' {
interface ServiceTypes {
graphql: Graphql & ServiceAddons<any>
}
}
export default async function (app: Application): Promise<void> {
const schema = buildSchemaSync({
resolvers: [__dirname + '/resolvers/*.resolver.ts'],
container: Container,
})
app.use(
'/graphql',
graphqlHTTP({
schema: schema,
graphiql: true,
})
)
}
and here's one of my resolver classes article.resolver.ts
import { Arg, Query, Resolver } from 'type-graphql'
import { Service } from 'typedi'
import { Application } from '../../../declarations'
import { Category } from '../types/category.type'
#Service()
#Resolver(Category)
export class CategoryResolver {
constructor(private readonly app: Application) {}
#Query((returns) => [Category])
async categories() {
try {
const result = await this.app.service('category').find()
return (result as any).data // TODO: Refactor to return result with pagination details
} catch (err) {
console.log('Categories resolver error', err)
return []
}
}
}
I can't do this.app.service() as this.app is undefined
Im a little confused on how dependency injection works in TypeGrapQL, any help is appreciated.
Thanks
I managed to make it work, here's my solution if anyone has the same problem:
I created a Graphql class decorated with #Service from typedi that takes in an app object as such
import { Service } from 'typedi'
import { Application } from '../../declarations'
#Service()
export class Graphql {
app: Application
//eslint-disable-next-line #typescript-eslint/no-unused-vars
constructor(app: Application) {
this.app = app
}
}
In my graphql.service.ts I initiated the class and passed down the instance to the typedi container
import { buildSchemaSync } from 'type-graphql'
import { Container } from 'typedi'
import { Application } from '../../declarations'
import { Graphql } from './graphql.class'
export default async function (app: Application): Promise<void> {
const graphql = new Graphql(app)
Container.set('graphql', graphql)
const schema = buildSchemaSync({
resolvers: [__dirname + '/resolvers/category.resolver.ts'],
container: Container, // Pass the container to the resolvers
})
// Initialize our express graphql server
}
And Finally in my resolvers I am decorating the resolver with #Service and injecting the graphql instance to the constructor:
import { Application } from '../../../declarations'
import { Graphql } from '../graphql.class'
import { Inject, Service } from 'typedi'
#Service()
#Resolver(Category)
export class CategoryResolver {
app: Application
constructor(#Inject('graphql') private readonly graphql: Graphql) {
this.app = this.graphql.app
}
// Queries and Mutations
}
This solved it to me, hope it comes with any help to you 😊
Im newbee for angular 7 and now trying to implement CanActive, but im getting error :
Can anyone guide me to overcome this. My code samples are as follows :
auth.guard.ts :
import { Injectable } from '#angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth-service.service';
import {Router} from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService,
private myRoute: Router){
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.auth.isLoggednIn()){
return true;
} else {
this.myRoute.navigate(["login"]);
return false;
}
}
}
Using a promise in an if condition is always a bad idea, since it does not get resolved. You could return the promise itself, using resolve to pass the resulting boolean further down the line:
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Promise<boolean> | boolean {
return new Promise(resolve =>
this.auth.isLoggednIn()
.then(status: boolean => {
if(status === false) {
this.myRoute.navigate(["login"]);
}
resolve(status);
})
.catch(() => {
this.myRoute.navigate(["login"]);
resolve(false);
// ... or any other way you want to handle such error case
})
}
}
Please try this:
return this.auth.isLoggednIn() ? true : this.myRoute.navigate(["login"]);
I got the SAME error message when I did the following:
canDeactivate(component: CreateEmployeeComponent): boolean {
if(component.createEmployeeForm.dirty) {
return confirm('Are you sure you want to discard your changes?');
}
return true;
}
So I solved the problem in the following way:
canDeactivate(component: CreateEmployeeComponent): boolean {
return component.createEmployeeForm.dirty
? confirm('Are you sure you want to discard your changes?')
: true;
}
I'm not sure it works for you, but you can at least give it a try.
I just got this same error.
The reason I got this was I had declared (in my routing module app-routing.module.ts) my guard to be canLoad but later on I changed the method (in guard file) to CanActivate, so naturally Angular got confused.
Check that the class given into routes (in this case MyGuardClass) {path: 'aPath', component: myComponent, canActivate: [MyGuardClass]} implements CanActivate as documented here
I'm just trying to remove a movie clip from the stage upon double clicking
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import fl.motion.MotionEvent;
public class Main extends MovieClip{
var thingeh:Things;
public function Main() {
thingeh = new Things;
stage.addEventListener(MouseEvent.CLICK, onClick);
stage.addEventListener(MouseEvent.DOUBLE_CLICK, onDouble);
}
public function onClick(event:MouseEvent)
{
addChild(thingeh);
}
public function onDouble(event:MouseEvent)
{
if(thingeh)
removeChild(thingeh);
}
}
}
public function onDouble(event:MouseEvent)
{
if( thingeh && contains(thingeh) )
{
removeChild(thingeh);
}
}
Also, You may want doubleClickEnabled = true within your constructor.
Do note, MouseEvent.CLICK gets fired TWICE along with a MouseEvent.DOUBLE_CLICK event.