Using external js to sort tables in Angular2 - javascript

I have a problem. Im creating an app in Angular2 using Semantic UI. In the documentation said that you can create a sortable table. it say that you have to import a tablesort.js and call $('table').tablesort() when the DOM is ready.
My problem start when it doesnt recognize that .tablesort is a method. It say that its not a method from Jquery so i dont know how to do work correctly
Here is my code:
import { Component, OnInit } from '#angular/core';
import { UserService } from "services/user.service";
import { Bet } from "models/bet";
import * as $ from 'jquery';
#Component({
selector: 'history',
templateUrl: 'history.component.html',
styleUrls: ['./history.component.css'],
})
export class HistoryComponent implements OnInit {
url: string;
bets = [];
constructor(private userService: UserService) {
this.url = 'http://localhost:3000/bets/history';
}
ngOnInit(): void {
this.userService.getHistory(this.url).subscribe(this.sucess.bind(this), this.error);
$('table').tablesort();
}
}
And in my index im importing:
<script type="text/javascript" src="semantic/components/tablesort.js"></script>
How can i do that Jquery recognize a external JS and can use the function from that JS.

Related

Adding OpenRouteService to Angular Application on Stackbliz

I added OpenRouteService to my Stackbliz application but cant get it working.
the Component looks like:
import { Component, OnInit } from '#angular/core';
import {Location} from '#angular/common';
import {Openrouteservice} from '/openrouteservice-js/dist/ors-js-client';
#Component({
selector: 'app-event-plan',
templateUrl: './event-plan.component.html',
styleUrls: ['./event-plan.component.scss']
})
export class EventPlanComponent implements OnInit {
constructor(private _location: Location) {
console.log("++++")
console.log(Openrouteservice)
}
ngOnInit() {
}
backClicked() {
this._location.back();
}
}
My problem is that it just doesnt get loaded. I added it as a dependency in the dependency section.
I made the project public here is the url - https://stackblitz.com/edit/angular-micwge?file=src%2Fapp%2Fevent-plan%2Fevent-plan.component.ts
You will have to change the way you import the library. The current way you import is looking for a named export from the library.
If you have allowSyntheticImports and esModuleInterop in your tsconfig.json use this:
import Openrouteservice from 'openrouteservice-js';
otherwise:
import * as Openrouteservice from 'openrouteservice-js';
Find your forked stacknlitz

Load multiple scripts in Component

I am new to angular 6. I just start learning angular 6. While creating a project i am stuck into error.
I am simply adding external scripts into my component and getting error
Here is my code
import { Component, OnInit } from '#angular/core';
import * as $ from 'src/assets/js/jquery-3.2.1.min.js';
import 'src/assets/js/countdowntime.js';
#Component({
selector: 'app-comingsoon',
templateUrl: './comingsoon.component.html',
styleUrls: ['./comingsoon.component.css']
})
export class ComingsoonComponent implements OnInit {
constructor() { }
ngOnInit() {
console.log($) // here is am getting output
}
}
Error:
Uncaught ReferenceError: jQuery is not defined at Object..
/src/assets/js/countdowntime.js (countdowntime.js:92)
Update your code
Add jQuery to your index.html or angular.json file
import { Component, OnInit } from '#angular/core';
declare var jQuery:any;
#Component({
selector: 'app-comingsoon',
templateUrl: './comingsoon.component.html',
styleUrls: ['./comingsoon.component.css']
})
export class ComingsoonComponent implements OnInit {
constructor() {
// load countdown
var c = document.createElement("script");
c.type = "text/javascript";
c.src = "src/assets/js/countdowntime.js";
document.getElementsByTagName("head")[0].appendChild(c);
}
ngOnInit() {
console.log(jQuery) // here is am getting output
}
}
You should be able to add jquery as a package and reference it in your component code, so it can get picked up by Webpack:
$ npm add jquery
Then inside your TypeScript code:
import * as $ from 'jquery';
...
export class FooComponent implements OnInit {
ngOnInit() {
console.log($);
}
}
Solution 1 :
Use Jquery types
Need to add types for jquery version.
you can find jquery types here
https://www.npmjs.com/package/#types/jquery
As typescript is strongly typed
For all items which we use in a component should have types
Solution 2 :
create a variable $ and assign its type to any
A workaround if you're not able to find type for the current jquery version which is
declare var $: any;
#Component({
selector: 'app-comingsoon',
templateUrl: './comingsoon.component.html',
styleUrls: ['./comingsoon.component.css']
})
inside your component life cycle check the value of the dollar, you will find jquery properties and method. Your error will be resolved
ngOnInit() {
console.log($)
}

Angular 6, Materialize: initializing javascript

I am new to Angular and Materialize. I am trying to initialize a carousel within my Angular component.
Materialize mentions three ways:
M.AutoInit();
or
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.carousel');
var instances = M.Carousel.init(elems, options);
});
or
$(document).ready(function(){
$('.carousel').carousel();
});
I have installed Materialize via node. I have both its CSS and JS as dependencies in my angular.json folder. The CSS styling works. I have tried these three methods within my ngOnInit lifecycle hook within my component. "M" is not recognized. I tried importing materialize:
import { materialize } from '../../../node_modules/materialize-css'
and
let m = materialize;
But this hasn't worked either.
I then installed jquery as a depedency and tried that method, but that doesn't seem to work either.
You should use the Materialize for Angular library. Asking how to use jQuery with Angular can get you a lot of downvotes.
https://www.npmjs.com/package/angular2-materialize
import OnInit from #angular/core library
declare const M: any; underneath imports
fire the M.AutoInit() function in ngOnInit() lifecycle hook
Example (where the component name is MediaComponent):
import { Component, OnInit } from '#angular/core';
declare const M: any;
#Component({
selector: 'app-media',
templateUrl: './media.component.html',
styleUrls: ['./media.component.scss']
})
export class MediaComponent implements OnInit {
constructor() { }
ngOnInit() {
M.AutoInit();
}
}
import { Component, OnInit } from '#angular/core';
declare var M: any;

Angular 4 jquery doesn't work

I am trying to use jquery to my Angular 4 app.I had followed all the steps to install jquery on my Angular 4.However jquery still dont work.
I had put the jquery code on the component like this.
home.component.ts
import * as jQuery from 'jquery'
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(db: AngularFireDatabase,public authService: AuthService,public
afAuth: AngularFireAuth,) {
$(document).ready(function(){
$("#showAppinfo").click(function(){
$("#appinfo").slideToggle();
});
});
ngOnInit()
{}
}
And my Html is the following
home.component.html
<h1>This is Home page!!</h1>
<h2 id="showAppinfo">Basic App-info</h2>
<ul class="list-group" id="appinfo">
<li class="list-group-item">Publiser: {{ (appinfo | async)?.Publisher }}</li>
<li class="list-group-item">Publication_Year: {{ (appinfo | async)?.Publication_Year }}</li>
<li class="list-group-item">Version: {{ (appinfo | async)?.Version }}</li>
<li class="list-group-item">Registered Users: {{ (appinfo | async)?.Rusers }}</li>
<li class="list-group-item">Languages: {{ (appinfo | async)?.Language }}(Only)</li>
</ul>
But nothing happens when I click on <h2 id="showAppinfo">Basic App-info</h2>. Can you tell my if I am using the jquery code in the correct place?? The problem is on code or on the jquery instalation??
The basic problem is that you're trying to manipulate your template in the constructor. But when your component constructor executes, #showAppinfo and #appInfo elements don't exist yet because the view has not been built.
Operations that depend on view elements need to be performed at the earliest in the ngAfterViewInit lifecycle hook
export class HomeComponent implements OnInit, OnAfterViewInit
...
ngAfterViewInit(){
// do your template manipulation here
}
You can test this with something like console.log($("#showAppinfo")) and you'll see that it doesn't log any element constructor(), but it does in ngAfterViewInit()
Following the steps that works for me:
Install jquery
npm install jquery
Install ts type
npm install #types/jquery
Add jquery.min.js in your .angular-cli.json:
"scripts": [
"../node_modules/jquery/dist/jquery.min.js"
]
Create a service to JQuery with the Token, Provider and Factory:
import { InjectionToken } from '#angular/core';
import * as $ from 'jquery';
export const JQUERY_TOKEN = new InjectionToken<JQueryStatic>('jquery');
export function jQueryFactory() {
return $;
}
export const JQUERY_PROVIDER = { provide: JQUERY_TOKEN, useFactory: jQueryFactory };
Add the Provider in Module:
#NgModule({
declarations: [
...
],
providers: [
JQUERY_PROVIDER,
...
]
})
Use DI in any component:
constructor(
#Inject(JQUERY_TOKEN) private $: JQueryStatic
)
Be happy :D
this.$('body').css('background-color', 'red')
Easiest and Shortest way possible to use jQuery in Angular 2/4
1st Step
From index.html
my-test-project\src\index.html
Type jQuery cdn below app-root tag.
...
<body>
<app-root></app-root>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</body>
...
2nd Step
my-test-project\src\app\test\test.component.ts
Go to your desired components .ts script.
import { Component, OnInit } from '#angular/core';
// this line will allow you to use jQuery
declare var $: any;
#Component({
...
})
3rd Step
my-test-project\src\app\test\test.component.ts
Test jQuery by logging 'I<3Cats' inside jQuery syntax $(() => { /* content here */ }).
export class TestComponent implements OnInit {
constructor() { }
ngOnInit() {
$(() => {
console.log('hello there!');
});
}
}
You can also use this technique with other javscript libraries. I don't know if this is safe but will sure help you. quite
i had an issue with jquery not working on bootstrap navbar and solved like this...
import { Component, OnInit, AfterViewInit, ElementRef } from '#angular/core';
//declare var $: any; //old code..
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit, AfterViewInit {
constructor(private elem: ElementRef) { }
ngOnInit() {
}
ngAfterViewInit() {
this.elem.nativeElement.querySelectorAll('.navbar-nav>li>a').forEach((el) => {
el.addEventListener('click', () => {
this.elem.nativeElement.querySelector('.navbar-toggler').classList.toggle('collapsed');
this.elem.nativeElement.querySelector('.navbar-collapse').classList.toggle('show');
});
})
//old code...
// $('.navbar-nav>li>a').on('click', function () {
// $('.navbar-collapse').collapse('hide');
// });
}
}
Not sure what slideToggle() is doing, but FYI in Angular if you added
#ref to h2..
you can then add
#ViewChild('ref')
h2El:Element;
in Typescript associated to the HTML.
to do equivalent of $("#showAppinfo")..
If you used this in the HTML
<h2 #ref (click)="handler()">...</h2>
you'd have click handler..
so in Typescript add
handler() {
this.h2El.slideToggle();
}
your onInit method was inside the constructor, try it in the following way
constructor(db: AngularFireDatabase, public authService: AuthService, public afAuth: AngularFireAuth) {
$(document).ready(function () {
$("#showAppinfo").click(function () {
$("#appinfo").slideToggle();
});
});
}
ngOnInit() { }}

In angular2, are there any methods just like $compile()? [duplicate]

I want to manually compile some HTML containing directives. What is the equivalent of $compile in Angular 2?
For example, in Angular 1, I could dynamically compile a fragment of HTML and append it to the DOM:
var e = angular.element('<div directive></div>');
element.append(e);
$compile(e)($scope);
Angular 2.3.0 (2016-12-07)
To get all the details check:
How can I use/create dynamic template to compile dynamic Component with Angular 2.0?
To see that in action:
observe a working plunker (working with 2.3.0+)
The principals:
1) Create Template
2) Create Component
3) Create Module
4) Compile Module
5) Create (and cache) ComponentFactory
6) use Target to create an Instance of it
A quick overview how to create a Component
createNewComponent (tmpl:string) {
#Component({
selector: 'dynamic-component',
template: tmpl,
})
class CustomDynamicComponent implements IHaveDynamicData {
#Input() public entity: any;
};
// a component for this particular template
return CustomDynamicComponent;
}
A way how to inject component into NgModule
createComponentModule (componentType: any) {
#NgModule({
imports: [
PartsModule, // there are 'text-editor', 'string-editor'...
],
declarations: [
componentType
],
})
class RuntimeComponentModule
{
}
// a module for just this Type
return RuntimeComponentModule;
}
A code snippet how to create a ComponentFactory (and cache it)
public createComponentFactory(template: string)
: Promise<ComponentFactory<IHaveDynamicData>> {
let factory = this._cacheOfFactories[template];
if (factory) {
console.log("Module and Type are returned from cache")
return new Promise((resolve) => {
resolve(factory);
});
}
// unknown template ... let's create a Type for it
let type = this.createNewComponent(template);
let module = this.createComponentModule(type);
return new Promise((resolve) => {
this.compiler
.compileModuleAndAllComponentsAsync(module)
.then((moduleWithFactories) =>
{
factory = _.find(moduleWithFactories.componentFactories
, { componentType: type });
this._cacheOfFactories[template] = factory;
resolve(factory);
});
});
}
A code snippet how to use the above result
// here we get Factory (just compiled or from cache)
this.typeBuilder
.createComponentFactory(template)
.then((factory: ComponentFactory<IHaveDynamicData>) =>
{
// Target will instantiate and inject component (we'll keep reference to it)
this.componentRef = this
.dynamicComponentTarget
.createComponent(factory);
// let's inject #Inputs to component instance
let component = this.componentRef.instance;
component.entity = this.entity;
//...
});
The full description with all the details read here, or observe working example
.
.
OBSOLETE - Angular 2.0 RC5 related (RC5 only)
to see previous solutions for previous RC versions, please, search through the history of this post
Note: As #BennyBottema mentions in a comment, DynamicComponentLoader is now deprecated, hence so is this answer.
Angular2 doesn't have any $compile equivalent. You can use DynamicComoponentLoader and hack with ES6 classes to compile your code dynamically (see this plunk):
import {Component, DynamicComponentLoader, ElementRef, OnInit} from 'angular2/core'
function compileToComponent(template, directives) {
#Component({
selector: 'fake',
template , directives
})
class FakeComponent {};
return FakeComponent;
}
#Component({
selector: 'hello',
template: '<h1>Hello, Angular!</h1>'
})
class Hello {}
#Component({
selector: 'my-app',
template: '<div #container></div>',
})
export class App implements OnInit {
constructor(
private loader: DynamicComponentLoader,
private elementRef: ElementRef,
) {}
ngOnInit() {} {
const someDynamicHtml = `<hello></hello><h2>${Date.now()}</h2>`;
this.loader.loadIntoLocation(
compileToComponent(someDynamicHtml, [Hello])
this.elementRef,
'container'
);
}
}
But it will work only until html parser is inside angular2 core.
Angular Version I have Used - Angular 4.2.0
Angular 4 is came up with ComponentFactoryResolver to load components at runtime. This is a kind of same implementation of $compile in Angular 1.0 which serves your need
In this below example I am loading ImageWidget component dynamically in to a DashboardTileComponent
In order to load a component you need a directive that you can apply to ng-template which will helps to place the dynamic component
WidgetHostDirective
import { Directive, ViewContainerRef } from '#angular/core';
#Directive({
selector: '[widget-host]',
})
export class DashboardTileWidgetHostDirective {
constructor(public viewContainerRef: ViewContainerRef) {
}
}
this directive injects ViewContainerRef to gain access to the view container of the element that will host the dynamically added component.
DashboardTileComponent(Place holder component to render the dynamic component)
This component accepts an input which is coming from a parent components or you can load from your service based on your implementation. This component is doing the major role to resolve the components at runtime. In this method you can also see a method named renderComponent() which ultimately loads the component name from a service and resolve with ComponentFactoryResolver and finally setting data to the dynamic component.
import { Component, Input, OnInit, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '#angular/core';
import { DashboardTileWidgetHostDirective } from './DashbardWidgetHost.Directive';
import { TileModel } from './Tile.Model';
import { WidgetComponentService } from "./WidgetComponent.Service";
#Component({
selector: 'dashboard-tile',
templateUrl: 'app/tile/DashboardTile.Template.html'
})
export class DashboardTileComponent implements OnInit {
#Input() tile: any;
#ViewChild(DashboardTileWidgetHostDirective) widgetHost: DashboardTileWidgetHostDirective;
constructor(private _componentFactoryResolver: ComponentFactoryResolver,private widgetComponentService:WidgetComponentService) {
}
ngOnInit() {
}
ngAfterViewInit() {
this.renderComponents();
}
renderComponents() {
let component=this.widgetComponentService.getComponent(this.tile.componentName);
let componentFactory = this._componentFactoryResolver.resolveComponentFactory(component);
let viewContainerRef = this.widgetHost.viewContainerRef;
let componentRef = viewContainerRef.createComponent(componentFactory);
(<TileModel>componentRef.instance).data = this.tile;
}
}
DashboardTileComponent.html
<div class="col-md-2 col-lg-2 col-sm-2 col-default-margin col-default">
<ng-template widget-host></ng-template>
</div>
WidgetComponentService
This is a service factory to register all the components that you want to resolve dynamically
import { Injectable } from '#angular/core';
import { ImageTextWidgetComponent } from "../templates/ImageTextWidget.Component";
#Injectable()
export class WidgetComponentService {
getComponent(componentName:string) {
if(componentName==="ImageTextWidgetComponent"){
return ImageTextWidgetComponent
}
}
}
ImageTextWidgetComponent(component we are loading at runtime)
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'dashboard-imagetextwidget',
templateUrl: 'app/templates/ImageTextWidget.html'
})
export class ImageTextWidgetComponent implements OnInit {
#Input() data: any;
constructor() { }
ngOnInit() { }
}
Add Finally add this ImageTextWidgetComponent in to your app module as entryComponent
#NgModule({
imports: [BrowserModule],
providers: [WidgetComponentService],
declarations: [
MainApplicationComponent,
DashboardHostComponent,
DashboardGroupComponent,
DashboardTileComponent,
DashboardTileWidgetHostDirective,
ImageTextWidgetComponent
],
exports: [],
entryComponents: [ImageTextWidgetComponent],
bootstrap: [MainApplicationComponent]
})
export class DashboardModule {
constructor() {
}
}
TileModel
export interface TileModel {
data: any;
}
Orginal Reference from my blog
Official Documentation
Download Sample Source Code
this npm package made it easier for me:
https://www.npmjs.com/package/ngx-dynamic-template
usage:
<ng-template dynamic-template
[template]="'some value:{{param1}}, and some component <lazy-component></lazy-component>'"
[context]="{param1:'value1'}"
[extraModules]="[someDynamicModule]"></ng-template>
In order to dinamically create an instance of a component and attach it to your DOM you can use the following script and should work in Angular RC:
html template:
<div>
<div id="container"></div>
<button (click)="viewMeteo()">Meteo</button>
<button (click)="viewStats()">Stats</button>
</div>
Loader component
import { Component, DynamicComponentLoader, ElementRef, Injector } from '#angular/core';
import { WidgetMeteoComponent } from './widget-meteo';
import { WidgetStatComponent } from './widget-stat';
#Component({
moduleId: module.id,
selector: 'widget-loader',
templateUrl: 'widget-loader.html',
})
export class WidgetLoaderComponent {
constructor( elementRef: ElementRef,
public dcl:DynamicComponentLoader,
public injector: Injector) { }
viewMeteo() {
this.dcl.loadAsRoot(WidgetMeteoComponent, '#container', this.injector);
}
viewStats() {
this.dcl.loadAsRoot(WidgetStatComponent, '#container', this.injector);
}
}
Angular TypeScript/ES6 (Angular 2+)
Works with AOT + JIT at once together.
I created how to use it here:
https://github.com/patrikx3/angular-compile
npm install p3x-angular-compile
Component: Should have a context and some html data...
Html:
<div [p3x-compile]="data" [p3x-compile-context]="ctx">loading ...</div>
You can see the component, that allow to compile simple dynamic Angular components https://www.npmjs.com/package/#codehint-ng/html-compiler
I know this issue is old, but I spent weeks trying to figure out how to make this work with AOT enabled. I was able to compile an object but never able to execute existing components. Well I finally decided to change tact, as I was't looking to compile code so much as execute a custom template. My thought was to add the html which anyone can do and loop though the existing factories. In doing so I can search for the element/attribute/etc. names and execute the component on that HTMLElement. I was able to get it working and figured I should share this to save someone else the immense amount of time I wasted on it.
#Component({
selector: "compile",
template: "",
inputs: ["html"]
})
export class CompileHtmlComponent implements OnDestroy {
constructor(
private content: ViewContainerRef,
private injector: Injector,
private ngModRef: NgModuleRef<any>
) { }
ngOnDestroy() {
this.DestroyComponents();
}
private _ComponentRefCollection: any[] = null;
private _Html: string;
get Html(): string {
return this._Html;
}
#Input("html") set Html(val: string) {
// recompile when the html value is set
this._Html = (val || "") + "";
this.TemplateHTMLCompile(this._Html);
}
private DestroyComponents() { // we need to remove the components we compiled
if (this._ComponentRefCollection) {
this._ComponentRefCollection.forEach((c) => {
c.destroy();
});
}
this._ComponentRefCollection = new Array();
}
private TemplateHTMLCompile(html) {
this.DestroyComponents();
this.content.element.nativeElement.innerHTML = html;
var ref = this.content.element.nativeElement;
var factories = (this.ngModRef.componentFactoryResolver as any)._factories;
// here we loop though the factories, find the element based on the selector
factories.forEach((comp: ComponentFactory<unknown>) => {
var list = ref.querySelectorAll(comp.selector);
list.forEach((item) => {
var parent = item.parentNode;
var next = item.nextSibling;
var ngContentNodes: any[][] = new Array(); // this is for the viewchild/viewchildren of this object
comp.ngContentSelectors.forEach((sel) => {
var ngContentList: any[] = new Array();
if (sel == "*") // all children;
{
item.childNodes.forEach((c) => {
ngContentList.push(c);
});
}
else {
var selList = item.querySelectorAll(sel);
selList.forEach((l) => {
ngContentList.push(l);
});
}
ngContentNodes.push(ngContentList);
});
// here is where we compile the factory based on the node we have
let component = comp.create(this.injector, ngContentNodes, item, this.ngModRef);
this._ComponentRefCollection.push(component); // save for our destroy call
// we need to move the newly compiled element, as it was appended to this components html
if (next) parent.insertBefore(component.location.nativeElement, next);
else parent.appendChild(component.location.nativeElement);
component.hostView.detectChanges(); // tell the component to detectchanges
});
});
}
}
If you want to inject html code use directive
<div [innerHtml]="htmlVar"></div>
If you want to load whole component in some place, use DynamicComponentLoader:
https://angular.io/docs/ts/latest/api/core/DynamicComponentLoader-class.html

Categories

Resources