and has 0 comments
This should be a simple question with a simple answer, but if you google for Angular Material tooltip styling or length or width you get different answers that are not always complete or even correct. The problem: you have something like <a matTooltip="some message" matTooltipClass="myTooltipClass" ... as per the examples easy to find. However, it doesn't seem to be working. The styling for myTooltipClass does not apply. Here are some points to check off while searching for the problem:
  1. Check whether myTooltipClass is defined in the component or the global CSS file. It should either be in the global CSS file (so it applies to everything) or your component should declare encapsulation: ViewEncapsulation.None
  2. Check the declaration of the class is specific enough. DO NOT use !important to fix this, although it would work. Try something like this: mat-tooltip-component .mat-tooltip.myTooltipClass {...}

To see if the class is applied, set the background-color property to red or something. If the class applies, you managed to define it correctly. If it applies partially, it's not specific enough. To change the width, use max-width. To make the tooltip wrap use white-space: wrap; and word-wrap: break-word;

As a reference, this is how the HTML looks for a rendered tooltip:
<div class="cdk-overlay-container">
<div class="cdk-overlay-connected-position-bounding-box" dir="ltr" style="top: 0px; left: 0px; height: 100%; width: 100%;">
<div id="cdk-overlay-1" class="cdk-overlay-pane mat-tooltip-panel" style="pointer-events: auto; top: 8px; left: 417.625px;">
<mat-tooltip-component aria-hidden="true" class="ng-tns-c34-15 ng-star-inserted" style="zoom: 1;">
<div class="mat-tooltip ng-trigger ng-trigger-state" style="transform-origin: left center; transform: scale(1);">Info about the action</div>
</mat-tooltip-component>
</div>
</div>
</div>

and has 0 comments
Caveat lector: while this works, meaning it compiles and runs, you might have problems when you are trying to package your work into npm packages. When ng-packagr is used with such a system (often found in older versions of Angular as index.ts files) it throws a really unhelpful exception: TypeError: Cannot read property 'module' of undefined somewhere in bundler.js. The bug is being tracked here, but it doesn't seem to be much desire to address it. Apparently, I have rediscovered the concept of barrel, which now seems to have been abandoned and even completely expunged from Angular docs.

Have you ever seen enormous lists of imports in Angular code and you wondered why couldn't they be more compact? My solution for it is to re-export from a module all the classes that I will need in other modules. Here is an example from LocationModule, which contains a service and a model for locations:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LocationService } from './services/location.service';
import { LocationModel } from './models/location-model';
 
@NgModule({
imports: [ CommonModule ],
providers: [ LocationService ]
})
export class LocationModule { }
 
export { LocationModel, LocationService };

Thing to note: I am exporting the model and the service right away. Now I can do something like
import { LocationModule, LocationModel, LocationService } from '../../../location/location.module';
instead of
import { LocationModule } from '../../../location/location.module';
import { LocationModel } from '../../../location/models/location-model';
import { LocationService } from '../../../location/services/location.service';

Update: the initial article was plaing wrong :) I fixed it now. The important change is that you need to npm link the dist folder, not the root folder of the plugin project.

So, the question arises when you want to change a module that is used (and tested) in another module. Let's say your normal flow is to change the version of the child package, then npm run packagr, then npm publish it, then npm install childModule@latest in the parent app. This quickly gets tiresome and leads to unrealistic version numbers.

A better solution is to use npm link. First, you go to your plugin/child module and you run npm run packagr. When it's done, go to the dist folder and run npm link. This will create a symlink in the global node_modules folder for your project's distribution package. Then, move to the parent module and run npm link <name-of-child>. The name of the child is the same as the name of the application. This creates a symlink in the parent module's node_modules to the global symlink created earlier.

Wait! A few gotchas, first:
  • careful with the operations that might change the content of the folder linked in node_modules, as they will change the actual source code of the plugin
  • after you finish with the work on the plugin, then delete the symlink, publish the child and reinstall @latest at the parent
  • make sure that the version of the plugin package in the parent is permissive (something like >=initialVersion), otherwise you might have problems with the version number you set in the plugin package.json file

Hope this helps.

Just a short info about HttpInterceptor, which is the Angular system of intercepting http requests, so you can do useful stuff like logging, error handling, authentication, etc. There are two npm packets for http, the old one is @angular/http and the new one is in @angular/common. While their interfaces are similar, HttpInterceptor only works for @angular/common/http.

Bonus thing: in the interceptor you are building, when you get the Observable<HttpEvent<any>> from next.handle, do not .subscribe to it, lest you will double all http requests (including adding items).

and has 0 comments
I am in the process of converting an old web site to Angular 5 CLI. Little technical value other than I need to understand the underlying concepts, but I needed to take some Javascript code and execute it in Typescript, the de facto language for Angular. And you hear that Typescript is a super set of ECMAScript, but it's not as easy to integrate existing code.

So, first of all, we are talking pure Javascript code, not set up as a module or anything more advanced. Let's say something like function say(message) { return 'I say '+message.content+' ('+messsage.author+')'; }. It's a simple function declaration receiving a message object with the fields content and author and returns a string. How to use it in Typescript, which is a strong typed language?

First of all, you need to load the script itself. The file can be added to angular.cli.json, in the scripts section, like this:
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
"assets/js/someJqueryThing.js",...

Next, in the Typescript file you want to execute the code, import the script:
import('someJqueryThing')
(note that it is not some import something from something else syntax, just the name of the script, so that it is bundled in for that page. But at this moment Typescript tells you there is no say method, and that's because you have not declared it for Typescript.

There are two options. One is to add a file called someJqueryThing.d.ts in the same folder with the .js in which you declare the signature of the say function, the other is to declare it in the .ts file you are running the Javascript from. The syntax, for this case, is
declare function say(obj:any):string;
You could declare an interface and specify what kind of object say receives
interface Message {
content:string,
author:string
}
declare function say(message:Message):string;
, or you can even declare var say:any;