Check out our Angular Book Series.

How can you listen for a Browser Event in Angular?

This question recently came up in StackOverflow, and I thought I'd cross post my answer because I think I nailed this one.

The poster wanted to listen for an event in Angular. In the bulk of cases, I would do this in your HTML:

/main
/webapp/your-dir-here<button (click)="eventH<an/dloeurtp(u$teDviernetc)t"or>y
>

And this inside your component method:

als
>e
v
en t H an d l e r (e v e n t){
console.log(event);
<c}on
fi
g

It is simple, well documented, and Angular already 'wraps' the bulk of events dispatched up from your HTML page.

However, the poster really wanted to access the eventsin TypeScript. This is doable, but becomes a bit more complex.

First, add a #value to the HTML element in your HTML Template:


<goal>copy-resources<button #myButton>
<
/

The #MyButton syntax allows you to reference the child in code using the @ViewChild metadata:



@ V i ew Ch i l d( 'myButton')
myButton: Element<Rgefo;
al
s

Then you should be able to call the methods on the native element to access the event:


myButton.nativeElemen<t.k/eiydd>own
() ;
<!m-y-B uthteorne. ntahtei vpehEalesmeen t.ykoeuy pnreeesds (-)-;
my>B
u
tto n . n a t i v e E l e ment.keyup();
myButton.n<apthiasvee>Elveamelnti.dbaltuer();

If at all possible, I try to avoid drilling down into the ElementRef like this. I think I did it once when I created a reusable toast style component for a client, but for normal development I stick with the event directives.

Angular 7 is out, learn all about it here!

Angular 7 is out.. Along with it, I updated all the books in the Learn With series.

This is a major update to the book text, because I finally ditched the SystemJS infrastructure I created in the Angular 2 days, in favor of the more popular Angular CLI. The Angular CLI has become a standard Angular dev tool, and the formal Angular docs and samples do not use the SystemJS approach at all anymore.

Get your updated Books here, and use the discount code LaunchDayGiftFromJeffry to get 25% off when you buy straight from us:

I put together a brand new demo of the app that the book teaches you to build if you want a video reminder of what is going on.

Why aren't Styles working with my Angular 6 Build?

I was working on an Angular 6 project that recently ran into a problem. All our styles were messed up when we created a production build. There are a lot of complaints about it here.

There seem to be two solutions that work for us and I'll go over both of them.

Move the Styles

The first solution is to remove all your style imports from the Angular.json. Then add them back into the main styles.scss using @imports. So, my Angular CLI styles looks like this:

>
"s
tyl es ": [
"s rc / s tyles.scss",
"node_modules/boo<tsgtrroauppI/ddi>stja/vcasxs.a/cbtooitvsattriaopn.css",
"node_modules/@swi<ml/agnreou/pnIgdx>-da
ta t a b l e / r e l e ase/assets/icons.css",
"n<odaer_tmiodfualcetsId/@>swimalcatnieva/tnigxo-ndatatable/release/themes/material.css"
<],
/

Open up the styles.scss and add them as imports:


@import "../node_modules<v/ebrootstsraipo/dni>st/2c.ss3/.b0ootstrap.css";
@import "../node_modules/@swimlane/ngx<-data/tavbleer/rseileoasne/a>ssets
/ic on s . c s s" ;
@import "../node_modules/@swimlane/ngx-datatable/r<eleas/ed/tehepmeesn/mdateernicaly.c>ss
";

The styles would now change to this:


"styles": [
"src/<satyrlteisf.ascctsIsd>",j
ax]b,
-a
p

This worked. I actually think I like putting the styles in the main styles.scss instead of the Angular.json. I prefer to stay out of the Angular.json as much as possible.

Change Extract CSS Value

The second option, and the one in which we chose to do for this project, was to change the extractCss value from true to false. Inside your Angular.json find the value:


"extractCss":<tgrrouuep
Id>

You'll find the value at projects.architect.build.configuration.product.extractCss

Change it to:


"extractCss":false

Now open up your package.json and find the build prod command:


"prod":"ng build"

Add the build-optimizer argument:


"prod":"ng build --build-optimizer"

This should address the issue.

When you create a normal build, the styles are minimized into a JavaScript file--styles.js--and then loaded on demand by Angular as needed. When you use extractCSS, the files are combined into a single CSS file instead of being created in a js file. Part of the minimization process seems to be screwing up the order that files are compressed, which of course affects the final CSS and why our styles were not showing up correctly.

This caused a few grumblings among my team about how borked Angular CLI is, but I still enjoy working with it.

How do I sort two ng-material table instances on the same component?

I have been doing some prototype work with the ng-material's table component. The table component is, basically, a DataGrid.

As part of this proof of concept work I put two separate tables inside the same ecomponent. The code worked well enough, but I had trouble getting both tables to sort.

To get a table to sort you need to add a ViewChild reference to the MatSort. In the HTML:


<table mat-ta<bl/e d[edpaetnadSeonucryce>]=
"ro w D a ta1" matSort >

<</ta/bdleep>end
en

Then you get a reference inside the component code:

<
/g r@ouVpieIwdC>h
i
ld ( M a t S o r t ) s ort: MatSort;

And attach the two together:

this to ge
t J SnOgNO nsIunpipto(r) t
{
- - >th
i
s. r o w D a t a1.sort = this.sort;
<}d
epe

The my missing magic from last week's post.

There is a problem once you add a second table. First create the two tables:

<gr
oupId<>tableo rmatg-.glatssafbilseh .[jdeartsaSeouyr.cie]n=je"rcotwData1" matSort >

</gr<ou/ptIda>bl
e>

< table mat-table [dataSource]=<a"rtriofwaDctatIad2>"je rmsaetyS-ohrkt2 >
</table>

Then get the ViewChildren:

d --
>

@V i e w C h i l d(MatSort) sort: MatSort;

<@Vi/edweCpheinldde(MnactyS>ort
) s o r t 2 : MatSort;

This will cause issues, because both variables are pulling the same MatSort value and only the first grid will sort.

The way to solve this is how you mark the table to get the matSort value:

e
<table mat-ta<ble/ [daarttaiSfoaurccteI]d=>
"r ow D a t a 1 " m a t Sort <#s!o-r-t 1=u"smea ttShoe rfto"llo>w
ing ar<ti/ftaacbtlIed >i
f you< dtaobnl'et mnaete-dt asbelrev l[deatt a2S.oxu rccoem]p=a"triobwiDlatiat2y" -m-atS>o
r
t # s o r t 2 = " m at So rt">
<!-- ar<ti/fatcatIbdle>>j
er
s

Now get the ViewChildren references like this:


@ViewChild('sor<t1'/)g rsoourptI:d M>at
So r t ;

@ V iewChild('sort2') sort2: MatSort<;a
rt
i

And associate the sort element with the data source:

ncies
>

n g O n I n i t () {
this.rowData1.s<odretp e=n dtehnisc.ys>ort
1;
t h i s . r owData2.sort = this.sort2;
< g rou}pI
d
>

Now both grids should sort properly.

Five Reasons My ngMaterial Table won't sort!

I've been doing some prototype work with the ngMaterial grid and had a problem where the grid would not sort. Here are a few things to check if this happens to you.

  1. Import the MatSortModule Module: Be sure that your @NgModule definition includes the MatSortModule:



    ja@vNag.Mloandgu.lIe(llega{lA
    rgu m ednetcElxacerpattiioonn:s :Er r[o
    rs w e rAep pdiCsocmopvoenreedn twh,
    il e r]e,i
    fy i nigm pSoysrttesm:D e[s
    cr i p t orB(r
    ow    ismeprlMeomdeuntlea,t
    i o n =o rBgr.ogwlsaessrfAinsihm.ajtieorseny.sjMaoxdbu.linet,e
    rn a l . XmlMRaototTOabbjleecMtodJuaxlbeP,r
    ov i d e rM$aGetnSoerratlM
    o    dcuolnet,r
    ac t s]=,
    { bojaovtasxt.rwasp.:r s.[eAxptp.CMoemspsaogneeBnotd]y
    Reade}r)}

        

    Without this, the sorting will not work.

  2. Specify the matSort header: Be sure to specify the matSort header on your table grid:

    eFuture
    $1.call(LRUH<ybtridCachea.bjlaev a:m1a1t5-)
    tab    alte o[rdagt.agSlaousrscfe]i=sh.hk"2r.uotwiDlaittaie"s.ca cmahteS.oLRrUtHy bcrliadsCsac=he$O"rmiagitn-TehlreevadaAtwiaorne-Fuzt8u"re$
    1.c>al
    l
    (LRU/Hyb/r irdeCsatch eo.fj atvhae: 11t1a)b
    le     adte fjiavnai.tbiaosne he/rjea
    va.util.con<cur/rteanbtl.Feu>tur
    eTa
    s

    Without that you won't be able to click on the headers.

  3. Wrap Your Data Source in a MatTableDataSource: If you do not wrap your own datasource--probably an array--in the MatTableDataSource class you'll have to write your own sorting algorithm to affect your data because it won't work out of the box.

    litie
    s. r e f ltehcitsi.onr.oiwnDtaetran a=l .nCelwa ssMRaetfTlaebcltioneHelDpeartIampSlo$u2r.cceo(mmpyuRteo(wCDlaatsasARrefrlaeyc)t;i
    onH
    e

    Do this because it makes your life easier.

  4. Tell the data source about your sort: Your MatTableDataSource does not know about the sort by default. Get a ViewChild instance to the sort in your code:

    ctio
    n. i@nVtieerwnCahli.lCdl(aMastsSRoret) fsolerctt:i oMnaHteSlopretr;I
    mp

    And apply that:

    nal.
    Cl a snsgROenfInlietc(t)i onH{el
    pe r I m pthli.sa.crcoewsDsa$t4a0.0s(oCrtl a=s stRheifsl.escotrti;o
    nH elp}er
    Im

    Hopefully you got this far and your table is sorting now.

  5. Write Your Own Sort: If you're avoiding using the MatTableDataSource for some reason, you'll have to write your own sort algorithm. In the HTML, listen for the matSortChange event:

    nHelper
    Impl.getAllMet<htoadbsl(eC lmaasts-Rteafbllee c[tdiaotnaHSeoluprecreI]m=pl."jraovwaD:a1t0a8")
        maatt Soorrtg .cgllasass=sfi"smha.th-ke2l.euvtaitliiotni-ezs8."re f(lmeacttSioornt.Chianntgeer)n=al."ColnaMsastRSeofrlteCchatnigoen(H)e"lpe>r
    I
    mpl./ge/t PrreesDt eosft rtohyeM ettahbolde (dCelfaisnsiRteifolne chterieo
    nHelperI<mpl/.tajbalvea:>20
    9)

    And in your code:

    ties.
    ca c hoen.MLaRtUSHoyrbtrCihadnCgaec(h)e.co{mp
    ut e ( L RUH/yb/r iddoC ascohmee.tjhaivnag: 3to1 5m)o
    d    ifayt yoorugr. gdlaatsa ssfoiusrhc.eh kh2e.ruet.
    il i tie}s.
    re
    f

I've found the documentation lacking for ngMaterial, but so far we plan on plunging ahead with it. Hopefully this helped someone out.

How does the HTML5 Pattern Attribute work?

I came across a question on StackOverflow about how to use Angular to restrict input to capital letters. Back in my Flex days, I'd use the restrict attribute for that, but I've never had to do that for HTML5.

I did some digging and found that HTML5 introduced a pattern attribute. I thought this is probably exactly what is needed and Angular doesn't need to get involved at all.

I threw together a quick sample.


<input type="text" pattern="[A-Z]*" name="sampleinput" />

Unfortunately, that wasn't nearly as helpful as I thought it might be. It does not restrict input, only gives guidance. In Firefox, it will turn red if you enter invalid characters:

If we change to all caps, the Firefox red warning goes away. A nice visual queue, but it does not restrict the input like I wanted.

Chrome on the other hand provides no feedback:

I didn't continue testing in different browsers, but I imagine there is similar inconsistencies.

You can control the error message, but using the title attribute, and even write your own code against an invalid event.

As best I can tell, there is no HTML5 way to restrict the input into a text field. But, after some searching, I found a few ways to do this with Angular, most involve adding a validator on the input.

You can also use CSS to force the text to uppercase:

emDescr i
pto r . java:705)
    at org.jvnet.hk2.i<nitnerpnuatl .tSyeper=viceL"otceaxtto"rImp ls.tryelifeyD=escri"ptteoxrt
-t
raentscf.o.r met:c .u.p
pe
rcase;"
name="sampleinput" />

However, that won't prevent the user from entering numbers.

How do I send JSON to a Server in Angular 2+?

I have a lot more trouble answering Angular questions on StackOverflow than I did answering Flex questions. The bulk of Angular problems seem to come from integrating different systems and libraries together. But, every once in a while I see a question that I seem to be the perfect person to answer. This question is about Sending JSON from Angular to PHP. I wrote a book about that.

When sending JSON to PHP--or Java or ColdFusion or any server side tech--you need to be sure to set the headers to application/json.

If you are using Angular 2, this is how you do it:

s = news Hweiaders(t);c
ho pt(i$onHeamdeerts.happendo('dContent-Type',) ' applicat{ion
/json ' );
lcet optaisones : 'ReGqueEstTO'p:t
io n s = n e w Requ/est/O paticocness(s URL{ headVerasr:ioapbtlieos
nHeaders});
t his.http.po s t ( s e rv/e/r $E_nGEdT[P"omyivnart"],)
J S O N P ayl o ad/,o/p tdiaotnas);
re
t

We create an instance of a RequestOptions object, and add the Headers onto it. The RequestOptions object is sent as part of your server request, in this case using a post() method. This is all part of the now deprecated Http library.

Angular 5 introduced the new HttpClient library, which does things a bit differently:

erverEndPoint,
J S$ON_PGaETy[l"omayvda,ro"pt]io)
ns)
;

You create a generic options object, and add an HttpHeaders() instance inside of it. Send that as the options argument to the http method, also a post().

Debug an Angular Application with a Chrome Plugin

I just discovered Augary, a Chrome Plugin for debugging angular applications. I can't believe I never came across this before.

Install Augary and then an Augary tab will appear as part of the Chrome Debugger tools. Here it is for the Learn With application:

Instead of trying to unravel the application through compiled source files and some guesses, Augaray models out the application for you and allows you drill into services, components, and routes to give you a deeper understanding of what is going on in your Angular application.

I've been playing around with it and it is pretty awesome.

How to specify the CSS extension when generating a Component with Angular CLI 6?

I created a brand new Angular CLI 6 project:

sult)
)n;
g n e w f o o -b-rstyelaek=;s
c ss

I wrote about this in another blog post.

Now generate a component:

r

n g g e n erat/e c/om Cproenaetne t smoymCe odmpa/tdai sHpleay
r

As expected, the new component is generated using SCSS:

That's good. But, what if you want to use something other than the project settings, like creating a normal CSS file as part of your new component or using the styleext command line argument:

$data
= njsgo ng_ednereatec ocdoem(pfiolneen_t gmeytC_ocmopnten/tost(h'eprhdips:pla/y /-i-nsptuytl'e)e)xt=css;

Now look at the generated files:

It changed the SCSS files from the first command to CSS Files in the second command. In case you are experimenting with different preprocessors for whatever reason, this has you covered.

How do I modify an existing Angular6 Project to use SASS?

If you haven't done so already, you may want to read last week's post about generating an Angular 6 project to use SASS instead of regular CSS files. There is a ton of documentation out there on how to do this for Angular 5 or before and they direct you to use ng set to modify the Angular config file. None of that works for Angular 6, because the

get/set have been deprecated in favor of the config command.

I had two problems. First, I found the documentation on how to use the config command a bit lacking. Second, you already have to know the properties you want to change before you can use the command.

Create a new project that is set to use SCSS and you'll find something like this:

sermo
de l "";
priomjpeocrtts ": {Ta{sk
M o d e l"my}A pfprSoemtToUs eC"S.S .": /mo{del
/ t a s k m o"dseclh"e;
ma
t
ic@sN"g:M odu{le(
{
"@sc hem/at/i costher/ asntguuflfa rhe:rceo
mp o npernotv"i:d ers{ :
[ U s e r M o d e l ," sTatsykMloedeexlt]"
: "}scs)
s"

}
},
....

This is what we want to create in our SASS-free project. Here is the command to add it to a new project:

You won't get a command line response, but your angular.json will not be updated.

If you want to CSS files that were already modified, you'll have to change them on your file system--and any code that references them such as a @component metadata. Be sure to open up the angular.json file and change the other defaults:

{

h e a de"rm(yA"pCpoNnotteSnett-TToyUpsee:C SaSp"p:l i{c
at i o n / j"asrcohni;t ecchta"r: s{et
= U T F - 8 " )";
bui
ld": {
"styles": [
"src/styles.scss"
],
"test": {
"options": {
"styles": [
"src/styles.scss"
],
....

Those are the only two references to the default styles folder for the main project, but be sure to do a file search through your Angular.json file just to make sure.

More Entries

All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.