Exploring the inner workings of Angular v4.4 and gaining insight into the roles of platformBrowserDynamic and PlatformRef

Recently, I have come into possession of an Angular 4.4 application that utilizes Webpack v3.5 and TypeScript v2.3.3. Struggling to decipher the imported code, I am at a loss understanding its functionality and correctness. To simplify matters for analysis purposes, I have extracted the following snippet:

In my main.ts file, the following declarations are present:

import { platformBrowserDynamic }  from '@angular/platform-browser-dynamic;'
return platformBrowserDynamic().bootstrapModule(AppModule).then...;

Essentially, it appears that platformBrowserDynamic is being called as a function in this block. Delving deeper into the @angular/platform-browser-dynamic/platform-browser-dynamic.d.ts file unveils the import statement:

export * from './src/platform-browser-dynamic';

Contained within @angular/platform-browser-dynamic/src/platform-browser-dynamic/platform-browser-dynamic.d.ts are these snippets:

import { PlatformRef, Provider } from '@angular/core';
export declare const platformBrowserDynamic: (extraProviders?: Provider[] | undefined) => PlatformRef;

This indicates that platformBrowserDynamic returns whatever PlatformRef signifies. Moving on to the @angular/core/core.d.ts file, there exists the export:

export * from './public_api';

Exploring further into @angular/core/public_api.d.ts reveals:

export * from './src/core';

The definition of PlatformRef stems from @angular/core/src/core.d.ts where we find:

export { createPlatform, assertPlatform, destroyPlatform, getPlatform, PlatformRef, ApplicationRef, enableProdMode, isDevMode, createPlatformFactory, NgProbeToken } from './application_ref';

Hence, the origin of PlatformRef becomes clear. In the @angular/core/src/application_ref.d.ts file, we encounter:

export declare abstract class PlatformRef { 
   abstract bootstrapModuleFactory<M>(
...
}

export declare class PlatformRef_ extends PlatformRef { ... }

It's established that PlatformRef is defined as an abstract base class, with PlatformRef_ acting as a concrete subclass – albeit without any explicit reference to this particular naming convention. However, per https://www.typescriptlang.org/docs/handbook/classes.html#abstract-classes:

Abstract classes serve as base classes for deriving other classes. Direct instantiation of abstract classes is not permitted.

Considering this information, what exactly does the invocation of platformBrowserDynamic() yield? Is it an Abstract Base Class (ABC)? Or perhaps an attempted invocation of said ABC, contradicting documentation guidelines? If indeed an ABC, the situation worsens given that the immediate call to platformBrowserDynamic initiates an abstract method within that ABC – leading to undefined outcomes. Despite functioning nominally, the mechanics behind its operation leave me perplexed.

Answer №1

When looking at the source code for angular 4.4's platform-browser-dynamic, you will find the following:

The function invocation of createPlatformFactory results in platformBrowserDynamic being an instance of a factory class.

A factory class is used to create objects without needing to know the specific class or when creating an object involves some complexity (such as in Angular components).

In this case, invoking the platformBrowserDynamic function creates a child class that extends PlatformRef, rather than an instance of PlatformRef itself since it is abstract.

Regarding where the actual instance is created, the child class extending PlatformRef is called PlatformRef_ and is defined within application_ref.ts.

This child class implements all necessary methods from the abstract parent class.

The instantiation of PlatformRef_ is handled by Angular's injector as it is marked with @Injectable and included in the providers list in platform_core_providers.ts.

The method returned by createPlatformFactory is responsible for creating a new platform based on the provided providers.

As for how a factory function programmed to return an abstract class can return a child class extending that class, it illustrates principles of object-oriented programming like abstraction, inheritance, and polymorphism. The factory simply promises to return something that follows the contract set by PlatformRef.

Answer №2

Initially, I intended to leave a comment but it seems like it might end up being lengthy...

You seem to have a few misconceptions about TypeScript and how it operates in relation to JavaScript, as well as package distribution in the JavaScript ecosystem.

Firstly, let's talk about `.d.ts` extension files - these are purely type declaration files used by the TypeScript transpiler. They do not contain executable code; rather, they provide information to the transpiler about the types of functions and variables. These files are generated (optionally) when bundling your code for distribution or sometimes maintained separately for libraries that do not natively support TypeScript but require compatibility. You could create a `my-function.d.ts` file in your application root with a simple declaration like:

declare function myFunction(a: string): string;

TypeScript will accept this declaration and allow you to use `myFunction` throughout your project, providing typings for it even if it is not actually implemented. This is useful for scenarios where TypeScript may not be aware of certain JavaScript libraries being loaded. For more on declaration files, check out: https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html

Regarding the `package.json` in Angular core pointing to a JavaScript file - this file contains transpiled source code that webpack uses for your bundled package. The source code obtained from npm is typically bundled for efficiency, along with type declaration files for TypeScript users. To access the original TypeScript source code before transpilation, you can visit the Angular GitHub repository at https://github.com/angular/angular. However, trying to understand Angular solely by inspecting npm packages is akin to examining binaries or NuGet packages in the realm of JavaScript development.

Another point to clarify is the return type `PlatformRef`, indicated as an abstract class. This does not mean it returns an instance of `PlatformRef` directly, but rather an instance of a class that extends or implements `PlatformRef`. By allowing different concrete implementations of `PlatformRef`, Angular enables developers to abstract data and event bindings efficiently for various platforms, ensuring portability of the application. Developers can focus on utilizing Angular tools to build portable applications without delving into specific platform intricacies.

In conclusion, understanding `PlatformRef` helps Angular manage application context for correct event and data binding across different platforms. It simplifies developer tasks by offering a consistent API regardless of the underlying platform. While exploring Angular source code can offer valuable insights in rare edge cases, starting with development guides and tutorials is recommended before diving deep into the source code.

If you aim to make your application compatible with unconventional platforms such as smart TVs or appliances, creating a custom implementation of `PlatformRef` and corresponding factory function would be essential.

Answer №3

Starting off, I want to emphasize that delving into the inner workings of libraries like Angular is not necessary for grasping the basics or getting it up and running smoothly. However, I understand the curiosity and drive to uncover the "magic" behind them, so I'll do my best to shed some light on this topic.

An abstract class serves a specific purpose in scenarios like this one. Essentially, an abstract class acts as a contract (similar to an Interface but possibly including core implementations usable by its inheriting child classes).

In this case, Angular commits to creating and providing you with an instance of a `PlatformRef`. This entity can vary depending on the platform being utilized, as outlined in the documentation:

In Angular jargon, a platform refers to the environment where an Angular application operates. While web browsers are the prevalent platforms for Angular applications, other possibilities include mobile device operating systems or web servers

The key point here is that Angular doesn't promise to hand you an instance of the abstract class itself; rather, it guarantees an instance of a class that adheres to the `PlatformRef` contract. You can utilize the methods defined within the contract without concern, as Angular takes care of verifying the platform and offering you the appropriate implementation of `PlatformRef` based on your current platform.

From the perspective of Angular developers, they needed to create methods that function consistently across all platforms. When you install Angular, you become their client, and the Abstract Class functions as their contractual agreement with you. In essence, even an Angular developer relies on this contract to incorporate additional Angular features without having to worry about platform intricacies.

In the excerpt provided, you may have noticed:

export const platformBrowserDynamic = createPlatformFactory(
    platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS)

This snippet hints at internally registered providers, with `createPlatformFactory` responsible for instantiating the `PlatformRef` contract. To offer a simplified illustration of this process, imagine something along these lines:

function createPlatform(): PlatformRef {
  if (typeof window !== 'undefined') { 
    return new BrowserPlatformRef();
  } 
}

class BrowserPlatformRef extends PlatformRef { /* ... */ }

As mentioned earlier, `PlatformRef` cannot be instantiated independently, leading `createPlatform` to ensure the return of a child class derived from `PlatformRef`, due to the prohibition of `new PlatformRef()` usage.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The `createAction` function does not preserve the data type when used with `ofType`

I'm currently developing a mobile application that allows users to choose snacks from a list of available options retrieved from an external API. To handle actions and dispatch API requests, I am utilizing redux-observable. Below is my existing code, ...

Do you know of any resources that provide tutorials on utilizing Epics within Redux Observables?

I've searched extensively for a comprehensive tutorial on epics, but haven't found one yet. const pingEpic = action$ => action$.filter(action => action.type === 'PING') .delay(1000) // Wait asynchronously for 1000ms before ...

I am looking to present a nested array within an array in a tabular format

This is the structure of my database: [{ "firstName": "Shaun", "salary": [ { "id":1, "rate": 250, }, { "id":2, "rate": 290, } ] },{ "firstName": "Julian", "salary": [ { "id":1, "rate": 750, ...

The count of bits is not producing the anticipated result

Attempting to tackle the challenge of Counting Bits using JavaScript, which involves determining the number of set bits for all numbers from 0 to N, storing them in an array, and returning the result Let me provide an explanation Input: n = 5 ...

The information in Vuex Store and Vue Component is not aligning and syncing properly

I am encountering an issue with a specific component in my Quasar project. I am currently utilizing a Q-table to display data pulled from a data field, which is supposed to sync automatically with the Vuex store. However, I am noticing that the data does ...

Adding URL parameters to route without disrupting ongoing routing actions

I have an Angular application that is typically accessed through a specific URL parameter, http://example.com/mypage?myId=1234 However, in cases where this parameter is not present, I need to dynamically generate an ID and append it to the URL. This means ...

Encountering TS2344 error when referring to the Component Ref in Vue.js during typing operations

I received a component reference on my FormCheckbox component from a patternlib. When I tried to incorporate the component into my own TestComp component, I encountered this TypeScript error that left me puzzled: TS2344: Type '{ name: string; mixins: ...

Unable to confirm the validity of an optional FormControl within Reactive Forms

I created a Reactive Form in my Angular application like this: <form [formGroup]="addressForm" (ngSubmit)="submitAddress(stepper)"> <h4>Delivery Address</h4> <hr /> <div class=&qu ...

How to transfer data between components in Angular 6 using a service

I'm facing an issue with passing data between the course-detail component and the course-play component. I tried using a shared service and BehaviorSubject, but it didn't work as expected. Strangely, there are no errors thrown, and the data remai ...

Troubleshooting the issue with the React Storybook Checkbox change handler functionality

I decided to create a checkbox component using React, Typescript, Storybook, and Styled-Components by following this informative tutorial: building-a-checkbox-component-with-react-and-styled-components. I had to make some adjustments to the code because I ...

Router failure resulted in an internal server error

When navigating to a page in my router, I make a REST API request to retrieve data from the server in the beforeEnter clause as shown below: beforeEnter: (to, form, next) => { getData().then( (response) => { ...

TypeScript unable to loop through object with string keys

My TypeScript service is responsible for populating an associative array: fun populateData(){ let tempArr; tempArr = []; this.service.get('Post', 1, 'true').subscribe( (response) => { this.loadingIcon = false; ...

React Native: Issue with the data section in FlatList

I encountered an issue while using Flatlist to address a problem, but I ran into an error with the data property of my Flatlist. The error message is not very clear and I'm having trouble understanding it ( No overload matches this call. Overload 1 of ...

Error: The communication channel abruptly closed before the expected response could be delivered

Before diving into the question, I want to mention that the only reference I could find related to this issue was on this Stack Overflow thread. The problem seemed to be associated with Wappalyzer, but it was reportedly fixed in version 4.0.1. Oddly enough ...

Comparing ngrx's createSelector method with Observable.combineLatest

Exploring the custom selectors from ngrx has left me in awe of their capabilities. Considering the example of using books for selectedUser, I find myself questioning the need for a custom selector like: export const selectVisibleBooks = createSelector(se ...

Guide to incorporating Bootstrap icons into an Angular application through programming techniques

Have you checked out the official bootstrap documentation for information on how to use their icons? https://i.stack.imgur.com/N4z2R.png I'm currently trying to understand the package and its usage. However, none of the options in the documentation ...

Tips for linking the search button to the corresponding input field in Angular

I'm working on a form that dynamically generates input fields using a for loop. Each input field has a corresponding search button. When a search button is clicked, it triggers a method to execute on all input fields. How can I make sure that the sear ...

The double deletion of all input causes a glitch in the two-way binding functionality

I attempted to prevent an input from being empty, but found that when using the method of selecting all text and then pressing backspace, the input only updates every other attempt. To see this issue in action visit: https://stackblitz.com/edit/angular-em ...

The error message "external.js: $ is not defined" indicates that

Recently, I integrated an external JavaScript file into my Angular 14 project. This JS file contains the event $('.class').click(). However, every time I launch the application on localhost, a message pops up in the browser stating that $ is not ...

Creating a PDF file with Angular 7: A step-by-step guide

I need to create a PDF report using data provided by the user and save it in an object. I've encountered methods that involve creating an HTML page, taking a screenshot, and then converting it to PDF. However, I'm seeking a solution to generate a ...