Check out our Angular Book Series.

How can I prevent an image from being dragged in my browser?

I've been doing some work on an Angular project with Dragula. I disabled our draggable div under certain conditions, but our users were still able to drag an image that lied within the Dragula div. Dragula prevented the drop, so our data was not put in a comprimising state, but it was confusing to our users that they could drag soemthing and not drop it.

Once I disabled Dragula on the div, the users were making use of default browser functionality. How can I prevent that?

There doesn't seem to be an easy cross browser way to do it, so I had to implement a few solutions.

First, for Chrome, I was able to use some CSS.


.no-drag{
-webkit-user-drag: none;
}

This web kit specific CSS extension prevents the item from being dragged.

Apply it to your imagE:


<img src="something" class="no-drag" />

But that did not solve the issue in Firefox. To do that I had to add the draggable attribute.


<img src="something" class="no-drag" draggable="false"/>

At this point it worked in both Firefox and Chrome and I stopped testing.

How do I set focus on an HTML element with Angular?

I've been working on a project where we wanted to load a screen and set it to the default state. It isn't that hard to do with Angular. This will show you how.

Set up a Basic Project

I started by creating a default Angular project with ng new. This will run you through the wizard and create a default component. For the purposes of this sample we're going to just modify the default component, app.component.

You can run the project using ng serve.

Create the Inputs

In a real world app there are plenty of ways to create your inputs. For the sake of this, we're going to create a bunch of inputs in a loop. Open up the app.component.html file:


<div *ngFor="let x of [0, 1, 2, 3, 4]">
<b>Input {{x}}</b>: <input #input> <button (click)="onClick(x)">Set Focus</button><br/>
</div>

The code uses ngFor to loop over an array. We give each input a label and a button. The button calls a method named onClick() which will give focus to the correct input.

Set focus on a click

Open up the app.component.ts file. First step is to get access to the ViewChildren:


@ViewChildren('input') inputs: QueryList<ElementRef>;

The input string in the ViewChildren() metadata refers to the #input text in the HTML input. Since we are referring to an array of inputs we use ViewChildren and QueryList instead of ViewChild and ElementRef. The QueryList is sort of like an array of all the HTML elements.

Now, create the onClick() method:


onClick(index) {
this.inputs.toArray()[index].nativeElement.focus();
}

The argument into the method is an index, referring to the item we want to put focus on. The method converts the QueryList inputs into an array using the toArray() method. Then it references the specific element using the index, accesses the nativeElement. The nativeElement references the actual HTML DOM element and is only supposed to be used or accessed sparingly. Finally, call the focus() method on the nativeElement.

We should be good to go.

Run the Code

Run the code in a browser. You should see something like this:

Click the buttons on the right and you should see focus being set to the proper input:

Now you know how to set focus on an input within Angular.

Play with the code here

Next week I'm going to show you how to test the onClick() method

How do I import something in Vanilla JavaScript

I've been doing so much with Angular and TypeScript that jumping back to regular JavaScript is a bit of a sticker shock. I've become very comfortable with a lot of the benefits of using TypeScript, specially how it magically handles importing other libraries.

I've been working on a book about RxJS, and using vanilla JavaScript instead of an advanced framework. This is part of my goal, when writing, to avoid as many dependencies as possible. And you shouldn't need to know about TypeScript in order to use a JavaScript library.

In TypeScript I might import things like this:


import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

And that works great. I stumbled a bit translating that into JavaScript, though. This is how it is done:


const { Observable } = rxjs;
const { tap } = rxjs.operators;

Instead of using the import tag, I create constants that point to the library. Instead of using the `from` we are assigning the constant at the relevant library. the Observable points to the full rxjs library--which I'm loading from a CDN using a script tag. The pipeable tap() function points to rxjs.operators.

Took me some trial and error to figure this out, so I hope this helps you.

How do I determine if an index is in a JavaScript Array?

You can use the in operator on a JavaScript array to determine if an index is in the array. This one surprised me.

Let's look at a sample. First, let's create an array:


wordArray = ['The', 'quick', 'brown', 'fox', 'jumped', 'over', 'the', 'lazy', 'dogs']

This array contains a bunch of strings, making up a sentence.

Normally if I wanted to determine if an item was in the array, I would get the index, like this:


index = wordArray.indexOf('The');

Then check the index against -1:


if(index !== -1){
console.log('index is in array')
} else {
console.log('index is not in array')
}

IF the index is -1; the item I searched for is not in the array. If it is something greater than -1; then the item I searched for is in the array. This works great.

A Colleague recently surprised me by using the in operator to perform the compare:


if(index in wordArray){
console.log('index is in array')
} else {
console.log('index is not in array')
}

This works, but is counterintuitive to me. I would have expected the in operator to look at items in the array; not to be used to compare the length.

But, alas; searching for an item with the in operator will return false; but searching for the index returns true


console.log('The' in wordArray); // return false
console.log(index in wordArray); // return true

Cool stuff. Play with the sample here.

Using `Object.assign()` - Type Assertions in TypeScript - Part 2

Last week I wrote about using `as type` in TypeScript to perform type assertions. The gist is that you convert a generic object, or JSON object into a custom object, like this:


myJSON as MyCustomClass

Once you do that, IDEs can introspect the object for code hinting purposes, and the TypeScript compiler will show errors if you access non-existent properties or methods. The problem is that this is just a compile time syntax and does not perform runtime type conversions. The use of get/set properties in the underlying object will not throw compiler errors, but will also fail in the UI code.

Thankfully there is another way.

Object.assign()

Built right into modern versions is Object.assign(). What this can be used for is move all the properties from one object into another. Any existing properties will be overwritten. Any new properties will be added to the object.

Here is a quick sample modeled after the link above:


const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
Object.assign(target, source);
console.log(target);
console.log(source);

The target object has two properties: a and b. The source object has two properties: b and c. After object.assign() is executed, the target object will have three properties: a, b, and c. The original value of b--2--will be replaced with the source's value for b--4.

Run this in a browser:

Simple enough.

Using Object.assign() as Type Conversion

How do we use an Object.assign() to convert regular JSON to an instance of our custom class? You can find our custom class sample in last week's article.


const testClassAssign = Object.assign(new TestClass(), {numbers : [1, 2, 3, 4]});
console.log(testClassAssign.sum); // returns 10

The first argument to the Object.assign() is a brand new instance of the TestClass. This instance gives us access to all the properties and methods in the class, including the get/set properties. The second argument is our custom JSON, or other generic object. All the properties from the generic object will be copied over to the new TestClass instance, essentially creating our full object:

You see in Chrome Dev tools that the new resulting class has the full type listed. Look at the console and you'll see the proper output for the second line:

This is what we wanted, and is important if you want to access any sort of custom method inside your class, while also touching on properties.

You can get all the samples from these two blog articles from my Github account.

Using `as type` - Type Assertions in TypeScript - Part 1

In an earlier article I wrote a bit about creating get/set properties in TypeScript. I am working on a project that uses a bunch of these, and sometimes they don't work.

Why do my get/set properties returned undefined? The method never executes, how can I fix it?

I'm going to show you why you're having problems and along the way talk about different forms of type conversions in TypeScript (and JavaScript).

The Setup

Let's start by creating a TypeScript class:


export class TestClass {
numbers: number[];
counter = 0;

get sum() {
this.counter++;
return this.numbers.reduce((accumulator, currentValue) =>
{
return accumulator + currentValue;
});
}
}

This class is named TestClass. It has three properties:

  • numbers: A regular property that contains an array of numbers
  • counter: A regular property that contains the number of the times that the sum was processed, perhaps a value you want to store for internal auditing purposes.
  • sum: A get property that returns the sum of all the values in the numbers array. Since this is a get property with no set, it is essentially read only and cannot set the value through traditional assignment.

Accessing a Get method with Simple JSON

When returning data from a server, I often get JSON, which is viewed as a generic object not tied to any specific TypeScript class. Look at code like this:


const testClassJSON = {numbers : [1, 2, 3, 4]};
console.log(testClassJSON.sum); // compile error

The first line hard codes a generic object, just like JSON that would be returned from the server to the application. this JSON matches the TestClass. But, the second line will give a compile error:

I can get this to compile if I tweak the code a bit differently:


const testClassJSON = {numbers : [1, 2, 3, 4]};
console.log(testClassJSON['sum']); // returns undefined

But, alas, that does not work, either:

The value is returned as undefined. The browser things this JSON value is a simple object:

There is no property named sum on a generic JavaScript object, and therefore cannot introspect special properties on the TestClass object.

For our get/set properties to work we need to perform some type of conversion from our generic JSON object to our formal type.

as TestClass

One version of Type assertion in TypeScript is similar to a cast that I've used in other languages.


const testClassAs = {numbers : [1, 2, 3, 4]} as TestClass;
console.log(testClassAs.sum); // returns undefined

Put this in your app and it should compile fine without any errors about the sum property not existing. That is progress. But, run the code and you see similar errors. The output to the console is undefined:

And the object in the debug tools is still seen as a generic object:

What gives? The `as type` is a TypeScript compile time assertion and has no affect at runtime. No conversion is made between your generic JSON class and your better typed TypeScript class. TypeScript does not even call this casting, because of the loosely typed nature of JavaScript. It calls it type assertion.

The angle bracket syntax of type assertion has the same problems.

For get/set properties to work, you must create an instance of that class somehow. I'm going to delve into that next week.

Understanding The JavaScript Reducer Function

Despite how long I've been creating JavaScript applications, I keep learning new things and discovering new little pieces of the language that I didn't know existed. Today I found the reducer function.

The reducer will loop over an array, with the intent of reducing the full array into a single value. The most common use case of this is to add up all the numbers in an array, like this:


console.log([1, 2, 3, 4].reduce((accumulator, currentValue) =>
accumulator + currentValue));

The reducer function accepts two arguments, the first is the accumulator and the second is the currentValue.

The first time the reduce function runs, it passes in the first two values from the array. The accumulator is the first value, 1 in this case. The currentValue is the second value,. the 2.

The second time the function is executed it returns the results of the first function run into the accumulator, and the third function. In this case, 3 is the results of the first run, and 3 is the third element in the array.

The third time the reducer is called it gets 6--the results of the third run of the function--and 4--the fourth item in the array. Then it has no more items to execute and returns the results.

Adding numbers in an array is a simple use case for this, but this could be used in much more advanced situations too, such as looping over an array of objects. Imagine you are creating a log display and want to show all the users who have edited something. Just use reducer to get the users list on each log item. Or maybe you're dealing with rights limited content and want to figure out what country the content is in; this could help if you loop over an array of 'rights metadata' objects.

Play with the code here.

Why can't Angular find the path() method on a Location object?

I'm writing some unit tests to test an Angular Router. In the test, I have code like this:


expect(location.path()).toBe('/something');

IntelliJ is giving me errors, saying it can't find the path value:

Clearly the path() method exists on the Angular Location object, so what was the cause of the error?

Apparently there is a JavaScript Location object.

The browser Location object does not contain a path() function even though the Angular one does.

Since Location exists natively, IntelliJ did not import the Angular library, and I didn't notice until I tried to run the code.

The fix is pretty simple. Just import the Angular Location library manually:


import {Location} from "@angular/common";

And you should be good to run your code and unit tests without any errors.

Creating Angular Directives Part 5 - Applying One Directive to Different Elements

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2, and part 3 that discusses input properties, and Part 4 which covers event dispatching.

We have created a directive named reverse which will toggle CSS Between two separate states.

Using the Directive Multiple Times

All our samples so far have been applying the styles to the button, but we can easily use this same directive on other elements; here it is in a p tag and a div:


<p [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

The directive in a p!
</p>
<div [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

The directive in a div!
</div>

The button is still in the view, and can be used to toggle:

Click the button and everything is reversed:

This is where we start to see the real power of encapsulating this in a directive. We are now writing simpler code than we would have if we were trying to do this using ngClass. Let's add four new styles into the create-attribute-directive.component.css:


.regular-red {
background: #ffffff;
color: #ff0000;
}

.reversed-red {
background: #ff0000;
color: #ffffff;
}

.regular-blue {
background: #ffffff;
color: #0000ff;
}

.reversed-blue {
background: #0000ff;
color: #ffffff;
}

The styles use red and white, or blue and white instead of our usual black and white. Apply them to HTML elements in create-attribute-directive-component.html:


<p [appReverse]="reversedState" regularCSSClass="regular-red" reversedCSSClass="reversed-red">
The directive in a p!
</p>

<div [appReverse]="reversedState" regularCSSClass="regular-blue" reversedCSSClass="reversed-blue">
The directive in a div!
</div>

The red style is applied to the p tag and the blue styles are applied to the div. Rerun the code:

And click to switch:

Final Thoughts

The bulk of Angular development I do is focused on creating custom components, not custom directives. But, understanding directives is important to being a good Angular developer because they give a different sort of flexibility that can be a benefit.

Be sure to check out my Learn With Series on Angular 8, which will cover this example in more detail, and even teach you all about Structural directives.

Creating Angular Directives Part 4 - Dispatching Events

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2, and part 3 that discusses input properties.

We have created a directive named reverse which will toggle CSS Between two separate states.

Dispatching Events

A directive can dispatch its own events, just like a component can. Let's add an event to the directive that will dispatch whenever the state changes. First, I'll add a new class:


export class CSSReversedEvent {
addedCSSClass: string;
removedCSSClass: string;
}

I put this class in the reverse.directive.ts file, instead of creating its own class file. It includes one value for the CSS Class that was removed, and one for the CSS Class that was added.

Now inside the ReverseDirective class, add the output event:


@Output() stateChange: EventEmitter<CSSReversedEvent> = new EventEmitter();

This uses the @Output() metadata to create the EventEmitter named stateChange. How look at the changeState() method:


changeState() {
const newState: CSSReversedEvent = new CSSReversedEvent();
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, this.regularCSSClass);
this.renderer.addClass(this.el.nativeElement, this.reversedCSSClass);
newState.addedCSSClass = this.reversedCSSClass;
newState.removedCSSClass = this.regularCSSClass;
} else {
this.renderer.removeClass(this.el.nativeElement, this.reversedCSSClass);
this.renderer.addClass(this.el.nativeElement, this.regularCSSClass);
newState.addedCSSClass = this.regularCSSClass;
newState.removedCSSClass = this.reversedCSSClass;
}
this.stateChange.emit(newState);

The first line in the method creates a new instance of the CSSReversedEvent class. The middle of the method will add the CSS Values onto this new object, depending on which state we are entering. The final name of the method will dispatch the event.

Open up the create-attribute-directive.html file and add in the stateChange event listener:


<button (click)="reverseState()"
[appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed"
(stateChange)="onStateChange($event)">

Reverse State
</button>
The event listener will call the onStateChange() event inside the create-attribute-directive.component.ts file:


onStateChange(event) {
console.log(event);
}

For simplicity I just outputted the event to the console.

Rerun the code and start clicking buttons:

During component initialization this event is dispatched twice. Once after the reversedState value is set, but before the regularCSSClass and reversedCSSClass are set. We see the event dispatching undefined for each class in this case. Then it is dispatched a second time after the initialization is complete. This is when the initial styles are applied to the button.

Click the button a few times to see the events continue to dispatch:

At this point in the series, you should realize that there is a lot you can do with directives.

What's Next?

For the last article in this series, I'm going to give a sample of applying the same directive to different elements.

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.