Angular $broadcast vs. $emit - diffs, pros and cons

Goal:

There always seems to be confusion over when to use $broadcast vs. $emit and can be hard to remember the scope affected by which one. Of course this will also have an impact on performance.

Details:

In either case, $broadcast or $emit, Angular uses $rootScope.$on and $scope.$on to listen to these events. Which one to use is up to the how far you want to expose the listener or subscriber to dispatched events.

  • $rootScope

    • $emit

      dispatches events upwards only by traversing the scope hierarchy from the bottom-up. Only $rootScope listeners will be notified of any changes since it is also the “root” scope. That means any $scope subscribers will not be notified. A simile of this would be when there are grandparents, parents and children in the room, the grandparents speak to each other but neither their children nor grandchildren here the conversation ~ old people only.
    • $broadcast

      dispatches the event downwards to all child scopes, regardless of how deep it hierarchy is. This is a truly expensive exercise and the digest cannot be cancelled. As long as any object is $dirty, the digest lifecycle will continue to cycle, up to 10 times until no more changes are found. A simile of this would be when there are grandparents, parents and children in the room, the grandparents let everyone to come eat dinner, the message is intended for all in the room (everyone as in all scopes in the ng-app).
  • $scope

    • $emit

      dispatches events upwards only by traversing the scope hierarchy from the bottom-up. This is intended to dispatch events to parents, all the way to the eventual $rootScope. However, none of the other children get notified. Let’s say you have a room with great-grandparents, grandparents, parents and children, four generations, 4-level deep scope and one of the children wants to share a secret with all their parents, grandparents and finally great-grandparents ($rootScope). None of the other children heard a thing!
    • $broadcast

      dispatches the event downwards to all child scopes, regardless of how deep it hierarchy is, but only to the $scope and not any of the $rootScope listeners. A simile would be when there are grandparents, parents and children in the room. Grandpa wants to share a Christmas gift idea with all of his children an children’s children, and so on, but he does not want grandma to know about it, it’s a surprise!

Here is a visual diagram to try and explain the scope impact:

image

Here is an example of $scope broadcasting and emitting and having one listener/subscriber listen to the event on $scope:

// displatch the event upwards:

$scope.$emit('someEvent', {

       msg: ’some data object’

});

// dispatch the event downwards:

$scope.$broadcast('someEvent', {

      msg: ‘can be some complex object or function’ // string or complex objects

});

// listen for the event in $scope:

$scope.$on('someEvent', function (e, data) {

      console.log(data.msg); // 'Data to send'

});

In order to cancel an event from bubbling up when calling $emit, simply stop call stop propagation:

$scope.$on('someEvent', function (e, data) {

       e.stopPropagation();

});

Be careful with naming conventions when broadcasting or emitting, just as with global namespace pollution you could also pollute the pub-sub event namespaces. I recommend a simple namespace hierarchies where the root follows a class-name pattern(nouns) and the sub-level some action. For example, if you are going to share shopping cart data with others and perform different actions on the shopping cart on different controllers, you may have something like:

$scope.$broadcast('cart:add'[, data]);
$scope.$on('cart:add', function (e, data) {...});

$scope.$emit('cart:delete'[, data]);
$scope.$on('cart:delete', function (e, data) {...});

$scope.$emit('cart:checkout'[, data]);
$scope.$on('cart:checkout', function (e, data) {...});

Keyboard short-cut to get your lost Google Chrome tabs back

Issues:

You just accidentally closed your Google Chrome browser, and oh boy, you lost all your open tabs and windows. Google Chrome has a really helpful short-cut to get them all back. You also have similar options in Firefox and other browsers but have to use their menu system to “Reopen closed tabs”.

The Solution:

In Google Chrome simply use this sort-cut keyboard hotkey:

Ctrl+Shift+T

If you’re not using Google Chrome, my question is: “Why not?” Smile

JavaScript–Adding months or days to a date

Goal:

Add moths or days (or other increments) to a date in JavaScript.

Solution:

var current = new Date();

var threeMonthsInTheFuture =  new Date(new Date(current).setMonth(current.getMonth() + 3));

for days use:

getDate()

for hours use:

getHours().

 

and so on….

EF Code First Migrations–Create Index with INCLUDE

The problem:

Using Entity Framework code first migrations to create a complex index that defines “INCLUDES” as part of the index. Yeah, good luck doing that using Entity Frameworks fluent notation using LINQ ModelBuilder. Btw, the example below is an ASP.Net Core 1.0 implementation.

The solution:

Plug into the Code First migrations pipeline by simply defining your own custom sql.

Create a “dummy” migration file and add the code below that is just using the model builder’s SQL method to run any custom sql. Again you should have an empty Up and Down method unless you made other mapping changes, which is OK, just add the SQL statement below. Of course you need to rename the index and fields you want to include in the index.

To create migrations file via command line, make sure you are in the project folder that contains the EF DbContext.

dotnet ef migrations add CreateIndexForInvoice –c <my context name>

It will create the empty migrations file, now add your custom index as in the example below. Note that if you already have an index with that name you will not be able to apply the migration successfully to the DB. A safer implementation would be to first check if the index already exists inside the SQL statement.

public partial class CreatIndexesForInvoice : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql(@"
            CREATE NONCLUSTERED INDEX [IX_Invoice_DateTime]
            ON [dbo].[Invoice] ([DateTime])
            INCLUDE ([Id],[Number])
        ");

    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropIndex("IX_Invoice_DateTime");
    }
}

 

How to enumerate an ENUM (C#)

Goal:

You have a C# ENUM and for some reason you would like to enumerate it. Perhaps you would like to return the enumerated list to the client’s ajax call rather than calling the DB table that represents the ENUM. For example you may have invoice statuses and want to build an anonymous list.

Result:

C# class:

public enum InvoiceStatus
{
    [Display(Name = "OPEN")]
    Open = 1,
    [Display(Name = "CANCELLED")]
    Cancel = 2,
    [Display(Name = "POSTED")]
    Posted = 3,
    [Display(Name = "VOIDED")]
    Void = 4,
    [Display(Name = "SUBMITTED")]
    Submitted = 5
}

MVC Controller:

[Route("getinvoiceStatuses")]

[HttpGet]

public IList<object> GetInvoiceStatuses()

{

var list = new List<object>();

foreach (var status in Enum.GetValues(typeof(InvoiceStatus)))
{
    list.Add(new
    {
        Id = (int)status,
        Description = status.ToString()
    });
}

return list;

}

JSON:

[{"Id":1,"Description":"Open"},

{"Id":2,"Description":"Cancel"},

{"Id":3,"Description":"Posted"},

{"Id":4,"Description":"Void"},

{"Id":5,"Description":"Submitted"}]