Angular 2 App scrolls to top on its own - javascript

Since the app is big I will try to simplify below:
TagComponent :
#Component({
selector: "tag",
template: `<div *ngFor="let a of arr">{{a}}</div>`
})
export class TagComponent{
#Input() arr: string[];
add(){
this.arr.push("abc");
}
}
AppComponent :
#Component({
template: `<p><tag [arr]="data"></tag></p>`
})
export class AppComponent{
data: string[];
//some other code
}
So, when add() is called, only the first time the app scrolls to the top automatically and this only occurs in Outlook Desktop which is running a modified version of IE 11. Its a bit difficult to understand the problem and give a solution but any hints as to what might cause this will also count as an answer.

Related

Angular 7 Dynamic variable name for imported component

In a simple angular app, I have created a test component like the one below:
test.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'test',
template: `<h1>I am a test</h1>`,
styles: [`h1 { font-family: Lato; }`]
})
export class TestComponent {
}
which I import in my app module like this:
app.component.ts
import { Component } from '#angular/core';
import { TestComponent } from './test.component';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
public TestComponent = TestComponent;
dynamic = "Test";
constructor(){
console.log(TestComponent);
console.log(this.TestComponent);
console.log(this['TestComponent']);
console.log(this[this.dynamic + 'Component']);
}
}
Getting help from this topic Angular 5 Dynamic variable name, I was able to get my component name dynamically (in the real example, the dynamic variable changes depending on an API call response).
My question is if there is any way to achieve the same result without having to pass the component as a local class variable, thus avoiding this line
public TestComponent = TestComponent;
without the this keyword the dynamic variable is not working, it gives me an error
console.log([this.dynamic + 'Component']);
I tried adding the code in a stackblitz but cannot seem to be able to share it (https://github.com/stackblitz/core/issues/215), but it is quite simple to copy the two files in a new empty stackbitz (https://stackblitz.com/edit/angular-f4ars5) to replicate.
Thanks in advance.
First you need to understand the following line
this['TestComponent']
In javascript you can access class properties in two ways. Class.property or Class["property"]. So when you are writing this["TestProperty"] you are effectively saying, Get AppComponentInstance.TestProperty
So console.log([this.dynamic + 'Component']); is like writing .TextComponent with nothing on the left side.
Now based on this, what are you trying to achieve exactly? Get the type or an instance of the type? What do you want to use the type for?
What you could do though would be to declare somewhere another global class and have these properties in them. Check this one for global variable declaration.
Your json could be something like this:
export class ComponentMapping
{
private TestComponent = TestComponent;
}
And then in your class access the test component accordingly.

Angular 2 : EXCEPTION: Error in app.component.html:1:108 caused by: too much recursion

I have downloaded the Angular 2 quickstart and it worked fine after all of the setup. I setup an express server and connected to that and the app continued to work fine. I made one change to use component templateUrl rather than template property and it stopped working. I have created a Plunker, https://plnkr.co/edit/BSnwkRdwwHFZZs808v4m?p=preview
to demonstrate this. Below is the AppComponent code where I switch between properties.
import { Component } from '#angular/core';
#Component({
selector: 'pm-app',
templateUrl: './app.component.html'
//template: `<h1>Hello {{name}}</h1>`
})
export class AppComponent {
name: string;
constructor(){
this.name = 'FasterLearnerII';
console.log("App Component Called");
}}
The Plunk also works fine if the AppComponent uses the template property but stops working when I switch to the templateUrl. I could find no error message with plunker but when I run in the browser the message I get is:
EXCEPTION: Error in app.component.html:1:108 caused by: too much recursion core.umd.js:3064:13
ORIGINAL EXCEPTION: too much recursion core.umd.js:3066:17
ORIGINAL STACKTRACE: core.umd.js:3069:17
getErrorPropertiesForPrototype/<#http://localhost:3030/node_modules/zone.js/dist/zone.js:936:17
The problem is not browser specific as I have tried it in Firefox, Chrome and IE.
Appreciate any thoughts on why this is not working.
you have to put full path,
this gonna work:
#Component({
selector: 'pm-app',
templateUrl: 'app/app.component.html'
//template: `<h1>Hello {{name}}</h1>`
})

Title service in angular2

I have used the Tile service of Angular, and title are getting set successfully.
Here is the code:
import { Component, OnInit } from '#angular/core';
import { Title } from '#angular/platform-browser';
#Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
constructor(private titleService: Title) { }
ngOnInit() {
this.titleService.setTitle('homepage first title');
}
}
but the problem is that when i check the title change through "view page source", none of the changes are getting reflected and the default title in index page is showing , what can i do to resolve this.
View page source is the plain index.html source file (like you have it on your/server file system). No JavaScript is executed or anything, so obviously nothing will show.
If you would like to have that the application is already compiled, take a look at NgUniversal, to leverage server side rendering. Not sure if that will work for your use-case though.

One Way Binding Angular2 Component With Pure Javascript

I was building an angular2 app in the expected language of typescript and I was having a ton of problem with 3rd-party typings and I was pulling my hair out with dealing with these typescript issue. So I boldly decided to instead give it a try in pure javascript. Crazy huh? Given the extreme lack of help to be found on the web.
But everything is working great with one exception, I can't get one way binding on a control to work. I am using an ES7 transpiler and so some of the annotations even work! So in the end it looks fairly similar to typescript (except for the typing of course).
app component html snippet
<results [results]="results"></results>
ResultsComponent
#Component({
selector: 'results',
templateUrl: '<div *ngFor="let result of results"><result [result]="result"></result></div>',
directives: [ResultComponent]
})
export class ResultsComponent {
#Input() results;
constructor(){};
}
In Typescript this was working fine. The results property in my ResultsComponent would be set to the value set in the app component. In the pure javascript version results is null. The code is reacting to the #Input decorator because if I take it away it complains about it being missing
EXCEPTION: Template parse errors:
Can't bind to 'results' since it isn't a known native property
but somehow the data is not coming through. Any ideas?
I found the answer in the inputs section of the Component decorator thanks to this link. I changed ...
#Component({
selector: 'results',
templateUrl: '<div *ngFor="let result of results"><result [result]="result"></result></div>',
directives: [ResultComponent]
})
export class ResultsComponent {
#Input() results;
constructor(){};
}
... to ...
#Component({
selector: 'results',
templateUrl: '<div *ngFor="let result of results"><result [result]="result"></result></div>',
directives: [ResultComponent],
inputs: ['results']
})
export class ResultsComponent {
constructor(){};
}
... and it works now!

Angular 2 Execute JS from file using AfterViewInit

Quite new to Angular 2, and after looking around for few hours I'd like to have some help.
I have a JS file with some generic functions. For example:
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
This file contains in fact way more code. As you can imagine, I'd like to enable tooltips of all components. I can't simply include this file in index.html because subcomponents aren't present (yet) when the file is loaded.
After some digging, afterViewInit() came up. This post suggests to copy/paste JS code into ngAfterViewInit(). That's the ugly way (in my opinion)...
So here I come with 2 related questions:
1# Is there a way to execute JS code when a child component is loaded? For example, something like:
// In app.component.ts
ngAfterChildComponentLoaded(){
// JS code here
}
This solution is quite interesting because I'm not forced to implement ngAfterViewInit() with the same content in all my components. But is it possible?
2# Is there a way to import JS code instrad of copy/paste it into ngAfterViewInit()? I don't want copy/paste 300 lines of JS code into 15 differents components (for obvious reasons).
Thanks a lot for your help!
See the following for how to get external js files for a particular component in angular 2/4:
import { Component, OnInit , AfterViewInit} from '#angular/core';
import { Router } from '#angular/router';
declare var $: any;
#Component({
moduleId: module.id,
selector: 'dashboard',
templateUrl: './dashboard.html',
styleUrls: ['./dashboard.css']
})
export class DashboardComponent implements OnInit,AfterViewInit {
constructor() {}
ngOnInit() {
}
ngAfterViewInit(){
$.getScript('assets/assets/build/js/custom.min.js');
}
}
Got a less-ugly solution, if someone has a better one I'll gladly accept his answer!
ngAfterViewInit(){
$.getScript('assets/js/myscript.js', function(){});
}

Categories

Resources