I am new to Angular world. There is something which confuses me while learning it, why we need to import any module two times : once through Javascript 'import' statement and then putting it in 'import' array?
Why need to import the same thing two times? Same goes with other code parts : need to first import 'component' and then again need to put the same in 'declarations' array of #NgModule.
Why need to do that? I am not getting it.
I'm guessing you're talking about your module files ?
First, you have this line
import { MyComponent } from './my-component.component';
this line allows the typescript compiler to say
Okay, I need the resources from that file, in this file.
In this case, you're importing a class.
The next line is
declarations: [MyComponent]
(Or imports or modules or providers etc.)
In this case, this is related to Angular : as you can see, you put those "imports" into the decorator of your module, #NgModule. This is internal Angular stuff, but it allows him to do the correct things with your classes. For instance, when you put injectable classes into the providers, it tells Angular to create single instances of thoses classes.
The keyword "import" is actually tells to import a module into the current module(module has class in it).
But after #NgModule whatever we are importing using imports keyword those are only single instances of the modules/classes imported previously.
Please correct me if I am wrong.
Related
I am making an angular project and have made required components and imported modules too. The main issue I see here ... is that we make 2 steps:
Add component, services, pipes, modules to the top adding respective files or folder locations
Add them in decorator (components, pipes, models go to declarations), (Modules to imports) and (services to providers).
There is an exception. Now, I expected that just like 'browser-module' (pre-fetched) or 'forms-module' (added manually) -- in the step-2 (ie, decorator array) there should be an injection or name-addition for 'ng-Module'. Why is it not there? Is this only exception or there is some other too? Shouldn't 'ngModule' be added in decorator would have been a consistent way?
Note: Code is not required as app it is working fine. The question is simple that if we are using a particular rule for all --
Components, Services, Modules, Pipes, Models and Interface -- why not
for 'ngModule'?
NgModule is a class marked by the #NgModule decorator. It is not a separate Module that is configured in your application.
It is required because you use #NgModule decorator at definition of your module. It's just a decorator and not a module. You need to import its script because you simply use it. You can think of it as #Input or #Output decorators. You import them within your components just to use it within component.
You can look at the code of NgModule
It is an interface
export interface NgModule { ...
However, BrowserModule is a module that decorates itself with #NgModule
Check the code
#NgModule({providers: BROWSER_MODULE_PROVIDERS, exports: [CommonModule, ApplicationModule]})
export class BrowserModule { ...
AOT Complier contains 2 phases.
Code Analysis Phase
2) Code Generation Phase
During Code Analysis Phase, with the help #ngModule class decorator AOT Compiler will get the metadata about the module. Using these details, it will create metadata.json for Compilation.
During Code Generation Phase, it will create module factories.
I started using import and export in javascript recently, but I am a bit confused. I'm not exactly sure what I'm supposed to export, and what I'm supposed to keep local to the file. I don't know how to express this nice in english, so here is a small section from my code:
The /client/js/Inventory.js file, module:
import {
$,
renderHTML,
game
} from "../main.js";
const template = {
titanium: {
name: "Titanium",
description: "Description here..."
}
}
export default class Inventory {
constructor(inventory) {
this._name = inventory.name;
this._description = inventory.description;
}
get name() {return this._name}
get description() {return this._description}
generate(id) {
renderHTML("inventory, `
<div class="inventory" id="${id}">
content here...
</div>
`);
}
static make(id) {
game.inventory[id] = new Inventory(template[id]);
game.inventory[id].generate(id);
}
and my /client/main.js file looks something like this:
import Inventory from "./js/Inventory.js";
const $ = (id) => document.getElementById(id);
const renderHTML = (id, str) => $(id).insertAdjacentHTML("beforeend", str);
const game = {
inventory: {}
};
Inventory.make("titanium");
export {
$,
renderHTML,
game
};
Since I'm exporting game object from the main.js file, does that mean a new game object is being created in the Inventory.js file after it's imported, or does that mean that the Inventory.js file can now access main.js file's game object?
Since I'm calling the classes inside the main.js file, do I also need to export the template object from the Inventory.js file, and import it inside the main.js file?
Exporting only the class works just fine, but I don't get how is the main.js accessing the template if it's not exported? Does it look in the Inventory.js file if none was found in the main.js or?
Thanks!
It's pretty simple. Modules are a structured way of sharing code or data between different pieces of code.
You export any functions or data that you wish to share with other modules that will load your module.
If you have no intention of sharing it or no need to share it, don't export it. If you do need to share it or some other module needs to be able to access it, you export it. Export is the means of sharing with other other modules.
You import any properties from other modules that you need to use in this module.
For imports, you only import what you need now. No need to import something you "might" need in the future. You can always just add the import at the time you actually need it.
For exports, you only export what you specifically intend to share now. If you find a need to share more later, you can always add another export later.
Code that is only used within this module does not need to be exported. In fact, one of the benefits of modules is that you can maintain code privacy or protection in a module because other code cannot access anything in a module that is not exported or shared somehow via an export.
You can logically think of exports as the "api" for your module. This is what other modules can call in your module.
You can logically think of imports as you specifying what "apis" you want to use from other modules.
When everything is in the global namespace (as with the original browser design), then there was no explicit export or import. Everything declared at the top level was just public and shared. This caused all sorts of problems, particularly as projects got larger and there got to be more and more files and then got even more complicated when you started trying to use third party code.
The module system is a structured way of saying that, by default, everything is private. You then explicitly export only the things you want to share. And, then when someone wants to use your apis, they explicitly import the apis they want to use. Each module lives in it's own scope so has its own namespace. Modules also make a very natural testable unit.
Before the standarization of Javascript modules, developers had build a whole bunch of different conventions to try to work-around the large flat global namespace in Javascript. It was not uncommon to encounter multiple conventions in the same project if you were using 3rd party libraries. For developers not trying to use a convention to solve this, code could get pretty messy with lots of potential for variable naming conflicts, accidental replacement of functions and a generally undocumented web of dependencies between files, etc... The standardized module design attempts to provide one common way of addressing these issues and, in the process, also make it a lot easier to write reusable, testable, shareable code.
Since I'm exporting game object from the main.js file, does that mean a new game object is being created in the Inventory.js file after it's imported, or does that mean that the Inventory.js file can now access main.js file's game object?
It means that Inventory.js can now export the one game object that was created in main.js. There is no implicit copying when you export or import.
Since I'm calling the classes inside the main.js file, do I also need to export the template object from the Inventory.js file, and import it inside the main.js file?
You only need to export things from inventory.js that you directly need to reference from some other file. Since main.js does not need to reference the template variable directory, there is no need to export it. The act of importing from inventory.js loads and runs that module. That makes the template variable available to all the code inside inventory.js which is all your code needs. So, no need to export it.
Exporting only the class works just fine, but I don't get how is the main.js accessing the template if it's not exported? Does it look in the Inventory.js file if none was found in the main.js or?
Exporting the Inventory class allows any other module to use that class and all its methods. The process of importing anything from inventory.js cause the module itself to get loaded so all the variables defined within inventory.js are active inside of inventory.js. When you create an Inventory object via the exported class, you are running code in inventory.js that has access to all the data in that module.
Thing of import as two steps. First load the module that is referenced (if it's not already loaded). Then, fetch the exports that you requested imports for.
In the docs for reactive forms, it's suggested that I should add the following lines to my app.module.ts.
import { ReactiveFormsModule } from '#angular/forms';
...
#NgModule({ imports: [ ReactiveFormsModule, ... ], ... })
export class AppModule { }
Then, in a later section, it's suggested to also add the following in my actual.component.ts.
import { FormControl, FormGroup } from '#angular/forms';
I've tried to skip the module part and only import stuff in the component, which seems to work, as far I can tell. It seems reasonable to me that if I'd do the opposite and added the module part, I wouldn't have to import in the components of that module. It's the combination of module part and component part that confuses me.
I don't understand the purpose of the both operations together. Why do they do that?
Importing at module level allows you to declare that module as a dependency of your module hence being able to use its providers, directives, pipes and other stuff in your templates.
Importing at component level allows you to use those classes in your typescript code.
Further explanation
In angular importing a module "merges" that module, so that when your template is compiled it recognizes template elements (components, directives and pipes) as angular elements.
In typescript and javascript in order to use code (classes, functions, constants) that is declared in another file or module you need to import it, in node you use the require() function, in typescript the import from expression.
So if you look at your code you will realize you are importing two different things, the module and the class, the first in order to merge that module and the second in order to use that class.\
Update
In typescript it is possible to have index files which are usually used to export elements whithout having to go deep into the folder structure, the file for '#angular/forms' exports the following (among other things):
export {AbstractControl, AbstractControlOptions, FormArray, FormControl, FormGroup} from './model';
export * from './form_providers';
Where form_providers has the declaration of FormsModule and ReactiveFormsModule.
Hence you are able to import both your module and your classes from one file.
In simple words :
Importing the module allows you to use the features of the module. Reactive forms allow you to create FormGroups with FormBuilders, that contain FormControls.
Importing the features in the component allows you to use those features. If you don't do it, your IDE won't know what FormGroup or FormControl means.
It may work without importing the features because they have been loaded in a bundle, but if you try to build your application without importing them, an error will be thrown.
Also, you need to import modules where you want to use their features. In Angular, modules don't inherit from their parents, so if you import the module at a too high level, you won't have access to it.
I'm in the beginning of a small web app, and have set it up to use JSPM and System.js for module loading. I have two files, app.js and util.js. In util.js, I am creating a function that gets a Handlebars template for me, and caches them in Handlebars.templates. The actual function has more to it than this, but lets say it just does this
import Handlebars from 'handlebars';
export function getTemplate(){
Handlebars.templates = 'HELLO THERE';
}
Then, in app.js, I do this
import {getTemplate} from 'util.js'
import Handlebars from 'handlebars'
getTemplate();
console.info(Handlebars.templates) //"HELLO THERE"
Why does Handlebars.templates persist? Is this something System.js does? Something Handlebars does?
ES6 Modules are singletons. Even though the module is imported by isolated files they both refer to the same instance. This is the expected behavior and is possible because export and import rely on bindings rather than copying values.
Since you may be coming from a CommonJS background you might find "What do ES6 modules export?" to be a good explanation about the difference in behavior.
I have bunch of Angular modules written in JavaScript and would like to import them into TypeScript. I tried using import and require, but it doesn't find my angular module since import checks for TypeScript Modules only.
import myModule= require('myModule');
Is there any other way to do this instead of converting my Js in TypeScript?
You cannot use modules defined using angular.module('my', []) directly from TypeScript. Such notation is used just to register a module inside internal angularJS object.
From good code prospective you have to redesign your angular modules to TypeScript/CommonJS/AMD modules and re-use them in your angular application.
But you can go another way:
create a hidden div element.
bootstrap an angular module you want to import on this div element. Here is link to angularJS documentation which may be helpful.
use next snippet to use service or whatewer else registered in your module: angular.element(document.getElementById('myhiddendiv')).injector.invoke(function(YourService: any) { YouService.doDirtyJob(); }).
But I would recommend to go with the first option.
The import module looks for JS files too...
import $Module = require("myModule");
This should work fine! In TypeScript you call the module with '$' and use it like:
$Module.createdWhateverFunctionYouMade(parameters);
In this case 'myModule' is the Javascript file.