Angular functions are performed twice when called in the html file - javascript

I tried to start an angular project, I've created a simple component and started a console.log in it but I have Confusing problem. when I calling a function in html file from ts file its run twice
TS:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.less']
})
export class HelloComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
log(val)
{
console.log(val);
}
test() {
let time = new Date()
console.log(time.getSeconds());
}
}
html :
hello works!
{{log('test')}}
{{test()}}
image log:
enter image description here

Where and how often do you call your component?
Can you produce a simple example on stackblitz?
Without any further info, we can just guess what it is.
You propably have called your component via '' twice.
Each instance will call all your template and hence its calling functions.

Related

unable to call javascript function from angular 13 component

There is a recent change introduced in Angular 13 where the old way of calling javascript functions from angular components isn't working anymore.
I am facing an issue with calling a javascript function from a specific component.
I already tried the usual way and here is my approach.
FILE: src\assets\js\main.js
(function($) {
"use strict";
function animatedProgressBar () {
$(".progress").each(function() {
var skillValue = $(this).find(".skill-lavel").attr("data-skill-value");
$(this).find(".bar").animate({
width: skillValue
}, 1500, "easeInOutExpo");
$(this).find(".skill-lavel").text(skillValue);
});
}
})(jQuery);
FILE: src\app\about-me\about-me.component.ts
import { Component, OnInit } from '#angular/core';
declare function animatedProgressBar(): any;
#Component({
selector: 'app-about-me',
templateUrl: './about-me.component.html',
styleUrls: ['./about-me.component.css']
})
export class AboutMeComponent implements OnInit {
//declare animatedProgressBar: any;
constructor() {}
ngOnInit(): void {
animatedProgressBar();
}
}
This code snippet throws an error: ERROR ReferenceError: animatedProgressBar is not defined
I checked the answer on This StackOverflow topic but it didn't work for me.
Looking forward to some valuable inputs on this issue.

NodeJS, Angular 2 | Executing method on Observable next

I'm currently getting started with Angular 2 and got stuck on something probably pretty simple:
I have a shared service chatMessageService.ts:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class ChatMessageService {
private messageList = new BehaviorSubject<string>("");
currentMessage = this.messageList.asObservable();
constructor() {
}
public addMessage(msg:string) {
this.messageList.next(msg) }
}
The service is imported by two components, one that calls it's addMessage function to add the message to the Observable and then my chatComponent.ts looks like this (shortened fpr convinience):
import { Component } from '#angular/core';
import { Message } from './message';
import { ChatMessageService } from './chatMessage.service';
#Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.css']
})
export class ChatComponent {
conversation: Message[] = [];
//.....
constructor(private chatMessageService: ChatMessageService) { }
addUserMessage(message) {
this.conversation.push({
content: message
});
}
ngOnInit() {
this.chatMessageService.currentMessage.subscribe(message => {this.addUserMessage(message);} )
}
}
My crisis arises at that last subscripion part. When I replace
{this.addUserMessage(message);}
with
{console.log(message)}
the message is printed out perfectly fine. If I call the addUserMessage()-method manually it works just fine. But when I call the method right there, with the message as argument, nothing happens. The method isn't even executed?
Thankful for your insights!
It looks like you need some buffering in the service.
Instead of BehaviorSubject, try
private messageList = new ReplaySubject<string>(10);
See working example: Plunker

How to call one method from another method in same Angular (Typescript) Component Class?

I am seeing a strange error where I try to call a method from another method and both method are in the same Angular 2 TypeScript component.
See in the below code that when ngOnInit() is invoked, it kicks off method1. method1 tries to invoke this.method2() . This is where the issue lies.
The error that appears is the following:
Error: Cannot read property 'method2' of undefined
Why is the this object undefined? How can I get around this so that I can call methods belonging to a class from other methods in the same class as I would, say in a language like Java?
import {Component, OnInit} from '#angular/core';
#Component({
selector: 'my-dashboard',
moduleId: module.id,
templateUrl: './dashboard.component.html',
styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
this.method1();
};
method1(): void {
this.method2();
};
method2(]): void {
console.log("hi");
}
}
I copied your exact code in this Plunker (but removed the unusual ']' from method2's argument) and it's working fine. I have added a button as well, to invoke Method1() as many times you want.
My suggestion is, remove moduleId: module.id from your component metadata and try again. Even the Plunker doesn't work when its in there.
UPDATE:
"All mention of moduleId removed. "Component relative paths" cookbook deleted (2017-03-13)" - https://angular.io/docs/ts/latest/guide/change-log.html
app.ts:
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<button (click)="method1()">Invoke Method 1</button>
</div>
`,
})
export class App implements OnInit{
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`
}
ngOnInit(): void {
this.method1();
};
method1(): void {
this.method2();
};
method2(): void {
alert("hi");
}
}
This isn't runnable so I can't test this solution myself, but try renaming the function to "this.method2" rather than just "method2".

How to access functions created in the Component outside of Angular2 using JavaScript [duplicate]

I am using a javascript Object that has a callback. Once the callback is fired I want to call a function inside an Angular2 component.
example
HTML file.
var run = new Hello('callbackfunction');
function callbackfunction(){
// how to call the function **runThisFunctionFromOutside**
}
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
packages: {'js/app': {defaultExtension: 'ts'}}
});
System.import('js/app/main')
.then(null, console.error.bind(console));
</script>
My App.component.ts
import {Component NgZone} from 'angular2/core';
import {GameButtonsComponent} from './buttons/game-buttons.component';
#Component({
selector: 'my-app',
template: ' blblb'
})
export class AppComponent {
constructor(private _ngZone: NgZone){}
ngOnInit(){
calledFromOutside() {
this._ngZone.run(() => {
this.runThisFunctionFromOutside();
});
}
}
runThisFunctionFromOutside(){
console.log("run");
}
How can i call the function runThisFunctionFromOutside which is inside App.component.ts
I basically followed this answer, but I didn't want my "outside" code to know anything about NgZone. This is app.component.ts:
import {Component, NgZone, OnInit, OnDestroy} from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
constructor(private ngZone: NgZone) {}
ngOnInit() {
window.my = window.my || {};
window.my.namespace = window.my.namespace || {};
window.my.namespace.publicFunc = this.publicFunc.bind(this);
}
ngOnDestroy() {
window.my.namespace.publicFunc = null;
}
publicFunc() {
this.ngZone.run(() => this.privateFunc());
}
privateFunc() {
// do private stuff
}
}
I also had to add a definition for TypeScript to extend the window object. I put this in typings.d.ts:
interface Window { my: any; }
Calling the function from the console is now as simple as:
my.namespace.publicFunc()
See also How do expose angular 2 methods publicly?
When the component is constucted make it assign itself to a global variable. Then you can reference it from there and call methods.
Don't forget to use zone.run(() => { ... }) so Angular gets notified about required change detection runs.
function callbackfunction(){
// window['angularComponentRef'] might not yet be set here though
window['angularComponent'].zone.run(() => {
runThisFunctionFromOutside();
});
}
constructor(private _ngZone: NgZone){
window['angularComponentRef'] = {component: this, zone: _ngZone};
}
ngOnDestroy() {
window.angularComponent = null;
}
Plunker example1
In the browser console you have to switch from <topframe> to plunkerPreviewTarget.... because Plunker executes the code in an iFrame. Then run
window['angularComponentRef'].zone.run(() => {window['angularComponentRef'].component.callFromOutside('1');})
or
window.angularComponentRef.zone.run(() => {window.angularComponentRef.componentFn('2');})
An alternative approach
would be to dispatch events outside Angular and listen to them in Angular like explained in Angular 2 - communication of typescript functions with external js libraries
Plunker example2 (from the comments)
Below is a solution.
function callbackfunction(){
window.angularComponent.runThisFunctionFromOutside();
}
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
packages: {'js/app': {defaultExtension: 'ts'}}
});
System.import('js/app/main')
.then(null, console.error.bind(console));
</script>
My App.component.ts
import {Component NgZone} from 'angular2/core';
import {GameButtonsComponent} from './buttons/game-buttons.component';
#Component({
selector: 'my-app',
template: ' blblb'
})
export class AppComponent {
constructor(private _ngZone: NgZone){
window.angularComponent = {runThisFunctionFromOutside: this.runThisFunctionFromOutside, zone: _ngZone};
}
runThisFunctionFromOutside(){
console.log("run");
}
}
An other approach without using global variables is to use pass a control object and bind its properties to the variables and methods to expose.
export class MyComponentToControlFromOutside implements OnChanges {
#Input() // object to bind to internal methods
control: {
openDialog,
closeDialog
};
ngOnChanges() {
if (this.control) {
// bind control methods to internal methods
this.control.openDialog = this.internalOpenDialog.bind(this);
this.control.closeDialog = this.internalCloseDialog;
}
}
internalOpenDialog(): Observable<boolean> {
// ...
}
internalCloseDialog(result: boolean) {
// ...
}
}
export class MyHostComponent {
controlObject= {};
}
<my-component-to-control [control]="controlObject"></my-component-to-control>
<a (click)="controlObject.open()">Call open method</a>
I had a similar situation when using the callback 'eventClick' of the fullCalendar library, whose callbacks are returning from outside the angular zone, causing my application to have partial and unreliable effects. I was able to combine the zone approach and a closure reference to the component as seen below in order to raise an output event. Once I started executing the event inside of the zone.run() method the event and it's effects were once again predictable and picked up by angular change detection. Hope this helps someone.
constructor(public zone: NgZone) { // code removed for clarity
}
ngOnInit() {
this.configureCalendar();
}
private configureCalendar() {
// FullCalendar settings
this.uiConfig = {
calendar: { // code removed for clarity
}
};
this.uiConfig.calendar.eventClick = this.onEventClick();
}
private onEventClick() {
const vm = this;
return function (event, element, view) {
vm.zone.run(() => {
vm.onSequenceSelected.emit(event.sequenceSource);
});
return false;
};
}
Just adding to #Dave Kennedy:
Calling the function from the console is now as simple as:
my.namespace.publicFunc()
1) If we try to access our component's public method from a different domain you will get caught into CORS issue (the cross origin problem, can be solved if both server and client code resides in same machine).
2) if you were to call this method from server using javascript, you will have to use window.opener.my.namespace.publicFunc() instead of window.my.namespace.publicFunc():
window.opener.my.namespace.publicFunc();

Angular 2 with TypeScript and Input decorator generate bad javascript ids

Hello guys,
I'm learning angular2 with Typescript and developing a new example I found some weird behaviour that maybe you can explain.
TypeScript Version:
1.8.10
Angular Version:
2.0.0-rc.1
Code
When I'm adding the #Input to a field, the generated js has errors in the generated ids:
This is the Typescript class I'm working on:
import { Component, Input, OnInit } from '#angular/core';
import { Event } from '../../model/event';
import { EventService } from '../../services/event-service';
#Component({
selector: "event-detail",
templateUrl: "event-detail.html",
providers: [EventService],
moduleId: module.id
})
export class EventDetailComponent {
#Input()
event: Event;
eventTypes : string[];
constructor(private service: EventService){
}
ngOnInit(){
this.loadEventTypes();
}
save(){
this.service.create(this.event).then(
event => this.event = event
);
}
cancel(){
this.event = null;
}
loadEventTypes(){
let response = this.service.listEventTypes()
.then(eventTypes => this.eventTypes = eventTypes);
}
}
And this is the error:
The following javascript code generated by the compiler is throwing the error because the event_1 doesn't exist.
__decorate([
core_1.Input(),
__metadata('design:type', event_1.Event)
], EventDetailComponent.prototype, "event", void 0);
Do you know what could be happen? Could a configuration be in conflict?
It looks like you did not load '../../model/event' module (perhaps it contains error, wrong path etc.).

Categories