Posts by "Vu Nguyen"

[Angular] ViewChild annotation returns undefined

While working on developing my own Web app, I got an issue with ViewChild annotation that always returns an object of undefined. I did an investigation and found out the problem is that I used ngIf directive within the component. Let’s see an example below and we are going to deeply dive into this one.

import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <div>
      <div>
          <input [(ngModel)]="inputValue" />
      </div>
      <div *ngIf="inputValue">
          <button #myButton>Click me</button>
      </div>
    </div>
  `
})

export class MyComponentComponent implements AfterViewInit {
  @ViewChild('myButton') button: ElementRef;

  constructor() { }

  ngAfterViewInit(): void {
    console.log(this.button);
    /*
    Result: undefined
    */
  }
}

Suppose I have an input field, and a button will be hidden by default. The button will only appear when the user types something in the text box to allow the user to click on it. In reality, we’re going to do other stuff. But in the case of this example, I’m using console.log(); to see the value of the element since I just wanted to show you the issue between ViewChild annotation and ngIf directive what I’m talking about. And the result of this console.log(this.button); is clearly undefined because the button element will not be created if the inputValue is null, it’s because ngIf directive will shape or reshape the DOM’s structure by adding or removing elements. And in this case, it’s not added yet. That’s why we got an object of undefined of the ViewChild.

So how will we fix that? We have two solutions for this one. Using hidden or style.display attribute.

Solution #1: Hidden attribute.

Instead of using ngIf directive, we now switch to use hidden attribute. Update the HTML code in the template, it is going to be changed like this. Since using the hidden attribute, the element is still generated in the DOM, and it’s just hidden from the UI so that the user will not see it.

<div>
    <div>
        <input [(ngModel)]="inputValue" />
    </div>
    <div [hidden]="!inputValue">
        <button #myButton>Click me</button>
    </div>
</div>

Solution #2: Style.display attribute

We’re going to bind display method to style.display attribute. In the class of ts file, display method will return a value of block or none that depends on inputValue. And the user will not see the button if display method returns block.

import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <div>
      <div>
          <input [(ngModel)]="inputValue" />
      </div>
      <div [style.display]="display()">
          <button #myButton>Click me</button>
      </div>
    </div>
  `
})

export class MyComponentComponent implements AfterViewInit {
  inputValue: string;
  @ViewChild('myButton') button: ElementRef;

  constructor() { }

  ngAfterViewInit(): void {
    console.log(this.button);
    /*
    Result: undefined
    */    
  }

  display(): string {
    if (this.inputValue) {
      return 'block';
    } else {
      return 'none';
    }
  }
}

Conclusions

Since the ngIf won’t add the element in if the expression is false. So the two solutions above are just to hide button from the UI in order for us to be able to get the Element from ViewChild.
Hope this helps you guys who have the same issue. If you have any questions or other workarounds, please add it to comment below.

Difference between IsNullOrEmpty & IsNullOrWhiteSpace

You could be familiar with these two methods of string. And today we are going to dive into them to see what the difference between them is.

What is it?

  • IsNullOrEmpty method indicates whether a specified is null or an empty string.
  • IsNullOrWhiteSpace method indicates whether a specified is null, empty, or consists of white-space characters.

How it works!

Let’s take a look at an example below.

static void Main(string[] args)
{
    Console.WriteLine(string.IsNullOrWhiteSpace("\t"));
    Console.WriteLine(string.IsNullOrEmpty("\t"));
    /* Output
    True
    False
    */

    Console.WriteLine(string.IsNullOrWhiteSpace("\n"));
    Console.WriteLine(string.IsNullOrEmpty("\n"));
    /* Output
    True
    False
    */

    Console.WriteLine(string.IsNullOrWhiteSpace(" "));
    Console.WriteLine(string.IsNullOrEmpty(" "));
    /* Output
    True
    False
    */

    Console.WriteLine(string.IsNullOrWhiteSpace(""));
    Console.WriteLine(string.IsNullOrEmpty(""));
    /* Output
    True
    True
    */
}

As you have seen, they returned 2 different results except the last one. In order to clarify this, we are now going to look at its code in more detail.

public static bool IsNullOrEmpty(string value)
{
    if (value != null)
        return value.Length == 0;
    return true;
}

public static bool IsNullOrWhiteSpace(string value)
{
    if (value == null)
        return true;
    for (int index = 0; index &lt; value.Length; ++index)
    {
        if (!char.IsWhiteSpace(value[index]))
            return false;
    }
    return true;
}

As you can see, IsNullOrEmpty method only checks the specified string whether it will be a null value or its length will be zero.  So that’s why this method has returned False of 3 cases above. Similarly, IsNullOrWhiteSpace method also makes sure our specified string whether it is null or empty. However, it has a little different from IsNullOrEmpty method is that white-space characters are defined by the Unicode standard. The IsNullOrWhiteSpace method interprets any character that returns a value of true when it is passed to the Char.IsWhiteSpace method as a white-space character. It is kind of useful when we have a method that converts from a string to a number as below. It’s because the condition !string.IsNullOrEmpty(strValue) will return True even if strValue parameter is a white-space or character escape sequences (“\n”, “\t”, …). And we will get an exception once Convert.ToInt32 method is called. And IsNullOrWhiteSpace will address this one.

static void Main(string[] args)
{
    string strValue = "\n";
    ConvertToInt(strValue);
}

public static int ConvertToInt(string strValue)
{
    if (!string.IsNullOrEmpty(strValue))
    {
        // This will throw an exception: System.FormatException: 'Input string was not in a correct format.'
        return Convert.ToInt32(strValue);
    }

    if (!string.IsNullOrWhiteSpace(strValue))
    {
        return Convert.ToInt32(strValue);
    }

    return 0;
}

Let’s see another example below. In order to remove all leading and trailing white-space characters from the current string, we will use Trim method. However, in the case below, we will get an exception since name is null and IsNullOrWhiteSpace works.

static void Main(string[] args)
{
    string name = null;
    GetItemByName(name);
}

public static Item GetItemByName(string name)
{
    if (!string.IsNullOrEmpty(name.Trim()))
    {
        // This will throw an exception: System.NullReferenceException: 'Object reference not set to an instance of an object.'
        return new Item();
    }

    if (!string.IsNullOrWhiteSpace(name))
    {
        return new Item();
    }

    return null;
}

Conclusion

I am showing you how these two methods work. IsNullOrWhiteSpace looks better, however, it depends on our situation what we need to handle and choose which one is suited for us.