Using Razor to generate Angular2 templates - asp.net-mvc

I am trying to use Razor to generate the html used in an Angular template. I am using Angular v 2.0.0. I have a Contract.cshtml that looks like:
<script>
System.import('contract.js').catch(function(err){ console.error(err); });
</script>
<my-contract>
<h1>Hello {{name}} this is a quick starter for angular 2 app</h1>
</my-contract>
A Contract.ts that looks like
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { ContractModule } from './app/Contract/contract.module';
platformBrowserDynamic().bootstrapModule(ContractModule);
A contract.component.ts that looks like:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { ContractComponent } from './contract.component';
#NgModule({
imports: [ BrowserModule ],
declarations: [ ContractComponent ],
bootstrap: [ ContractComponent ]
})
export class ContractModule { }
And a contract.component.ts that looks like:
import { Component } from '#angular/core';
#Component({
selector: 'my-contract'
})
export class ContractComponent {
public name = 'Nigel Findlater';
consturctor() {}
}
When I run this I get
Error: Error: No template specified for component ContractComponent
at DirectiveNormalizer.normalizeDirective (http://localhost:2600/lib/#angular/compiler/bundles/compiler.umd.js:13476:21) at RuntimeCompiler._createCompiledTemplate (http://localhost:2600/lib/#angular/compiler/bundles/compiler.umd.js:16869:210)
at eval (http://localhost:2600/lib/#angular/compiler/bundles/compiler.umd.js:16807:43)
at Array.forEach (native)
at eval (http://localhost:2600/lib/#angular/compiler/bundles/compiler.umd.js:16805:50)
at Array.forEach (native)
at RuntimeCompiler._compileComponents (http://localhost:2600/lib/#angular/compiler/bundles/compiler.umd.js:16804:45)
at RuntimeCompiler._compileModuleAndComponents (http://localhost:2600/lib/#angular/compiler/bundles/compiler.umd.js:16741:39)
at RuntimeCompiler.compileModuleAsync (http://localhost:2600/lib/#angular/compiler/bundles/compiler.umd.js:16732:23)
at PlatformRef_._bootstrapModuleWithZone (http://localhost:2600/lib/#angular/core/bundles/core.umd.js:6954:29)
Evaluating http://localhost:2600/contract.js
Error loading http://localhost:2600/contract.js
I think the error is in contract.component.ts, but I don't know how not to specify a template here

Angular2 is not designed to be used with Razor generated templates. It is best to allow Angular2 to handle all the routing and not use MVC because this adds an unnecessary dependency which makes the project harder to test.

I use Angular to offload a lot of work from the server to the client and host complex websites using much less resources. Those websites are not SPAs.
In that context it can be really useful to use ASP.NET router and razor generated templates (sometimes precompiled).
The only problem I faced in using razor generated templates in Angular was the way webpack was configured.
After removing the angular2-template-loader everything worked smoothly.

Related

How can I use React Hooks with ReactJS.NET?

We are currently migrating our frontend from jQuery to Reactjs.NET. We are using React 16.8 which allows us to use React Hooks instead of classes.
We setup our project successfully and tried it first with classes and server side rendering which worked well, but my team rather use React Hooks. I tried using Webpack + Babel to transpile .jsx files since it didn't work anymore using only razor helper #Html.React(), but I still get the same error from my component.
We are using Asp.NET 4.x and NET framework 4.7.
This is my view children.cshtml
#Html.React("ChildrenForm", new {
familyTiesId = Model.FamilyTiesId
},
serverOnly:true
)
This is my ReactConfig.cs:
namespace Nop.Web
{
public static class ReactConfig
{
public static void Configure()
{
// If you want to use server-side rendering of React components,
// add all the necessary JavaScript files here. This includes
// your components as well as all of their dependencies.
// See http://reactjs.net/ for more information. Example:
ReactSiteConfiguration.Configuration
.AddScript("~/Scripts/Components/Customer/ChildrenForm.jsx");
JsEngineSwitcher.Current.DefaultEngineName = V8JsEngine.EngineName;
JsEngineSwitcher.Current.EngineFactories.AddV8();
}
}
}
My component:
import React, { useState, useEffect } from 'react';
const ChildrenForm = (props) => {
const [ familyTiesId, setFamilyTiesId ] = useState(props.familyTiesId);
...
}
It should work, but instead I get:
SyntaxError: Unexpected identifier
Line 20: #Html.React("ChildrenForm", new {
Line 21: ddtl = Model.DDTL,
Line 22: listFamilies = Model.ListFamilies,
...
[JsCompilationException: SyntaxError: Unexpected identifier
at ChildrenForm.jsx:6:8 -> import React, { useState, useEffect } from 'react';]
JavaScriptEngineSwitcher.V8.V8JsEngine.InnerExecute(String code, String documentName) +258
React.ReactEnvironment.EnsureUserScriptsLoaded() +548
It seems like we cannot import files when using razor helper #Html.React and server side rendering.
How can I do an import and use React Hooks while server side rendering?
Instead of having to import it, you can just use:
const [ familyTiesId, setFamilyTiesId ] = React.useState(props.familyTiesId);
Just call useState directly instead of importing.

Angular 5 + Polymer: Styles of Polymer components with and without Origami

I'm working on an Angular 5 project (which I generated with the Angular CLI), using Bower for front-end dependencies. All the dependencies I need for my project are custom polymer components. I originally was able to get this project to work by using the Origami project, however I'm finding that I'd rather not use the project if possible since Polymer 2 and Angular 5 are meant to work quite well together now. The only place I've used the Origami project is in app.module.ts, where I import the PolymerModule from #codebakery/origami like so:
app.module.ts:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
import { HttpModule } from '#angular/http';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { PolymerModule } from '#codebakery/origami';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AnalysisComponent } from './analysis/analysis.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { SemtkService } from './services/semtk.service';
#NgModule({
declarations: [
AppComponent,
AnalysisComponent,
DashboardComponent
],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
imports: [
HttpModule,
BrowserModule,
AppRoutingModule,
FormsModule,
PolymerModule.forRoot() // Only import .forRoot() once and at the highest level
],
providers: [ SemtkService ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
In trying to delete the origami project, I've commented out the line PolymerModule.forRoot(), from the imports array. When I do this, the Polymer components seem to loose their styling.
Here is the page WITH the PolymerModule.forRoot() import:
page WITH import
And here is the page WITHOUT the import:
page WITHOUT import
Any ideas about what I could do to fix this would be welcome - thanks!
Author of Origami here, there's a service the library provides at the application root that registers Angular component styles with ShadyCSS (needed for #apply mixin support for all browsers and custom properties for browsers that don't support them).
https://github.com/hotforfeature/origami/blob/v2/origami/src/style/shared-styles-host.ts
You could either include that one service and provide it at your app's root, or write your own service that does something similar. Once Angular's styles are registered with ShadyCSS, any variables/mixins you define in Angular will be applied in Polymer.

how to use angular2 in mvc5 areas?

i have a sample mvc5 project and i used my first angular 2 modules successfully on this project. now i want to create new module inside my mvc areas. so i created new area with a .tsfile named app.components in my area solution! like what you see below:
import { Component } from '#angular/core';
#Component({
selector: 'area-app',
template:`<p>imanArea</p>`
})
export class areacomponent {<<bring below error!!!!!!!!!!!
name = 'dd';
}
experimental support for decorators is a feature
that is subject to change in a future release. set the
'experimentaldecorators' option to remove this warning
and second is from my root project rootproj/app/app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms'; // <-- NgModel lives here
import { AppComponent } from './app.component';
***below error for this line***
import { AreaAppComponent } from './Areas/SampleArea/app/app.areacomponent'
#NgModule({
imports: [BrowserModule, FormsModule],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Cannot find module'./Areas/SampleArea/app/app.areacomponent'
i checked my path and file names!! every thing is right but it doesn't find my path!
for more information i have to say all my essential angular files are in my root project and my app.module is inside a folder named app
means: rootProj/app/app.module and rootProj/app/app.component.spec
is it possible to use angular2 and mvc-Area together in one project?? i didnt find any source about that.
I actually use WebAPI to use Angular 2.
Back and Front-End are going to be in different project folders. And you will work with restful services.

Angular 2 and ActionCable integration

I'm trying to make a Angular2 app (bootstrapped with angular-cli) work with Rails's ActionCable by integrating this lib on the frontend https://github.com/mwalsher/actioncable-js
I npm installed the lib,
added this to angular-cli-build.js
'actioncable-js/index.js',
and this in system-config.ts:
/** Map relative paths to URLs. */
const map: any = {
'moment': 'vendor/moment/moment.js',
'ng2-bootstrap': 'vendor/ng2-bootstrap',
'lodash': 'vendor/lodash',
'actioncable-js': 'vendor/actioncable-js'
};
/** User packages configuration. */
const packages: any = {
'ng2-bootstrap': {
format: 'cjs',
defaultExtension: 'js',
main: 'ng2-bootstrap.js'
},
'actioncable-js':{
main: 'index.js'
},
'moment':{
format: 'cjs'
},
'lodash':{
main: "lodash.js"
}
};
added this to my component:
import { ActionCable } from 'actioncable-js';
but the build errors with this message:
Cannot find module 'actioncable-js'.
anyone has any idea why?
My guess is typings are missing, but I'm not sure how to fix this.
Rails has since released an official actioncable package here:
https://www.npmjs.com/package/actioncable
No there is no problem with typings. What you are missing is how to use Javascript library in angular 2 typescript application. If you want to use JavaScript library in your TypeScript application, then you need to import the library import 'actioncable-js' and then you have to declare the variable. declare let ActionCable:any This tells typescript we have a global variable ActionCable present in our application. Now you can access it in your angular 2 component implementations and do whatever you want to do. You can read the discussion here.
angular-cli.build.js
vendorNpmFiles: ['actioncable-js/**/*.js']
systemjs.config.js
map:{ 'actioncable-js':'vendor/actioncable-js/dist/action_cable.js'}
package:{'actioncable-js': defaultExtension: 'js'} }
`
app.component.ts
import 'actioncable-js';
declare let ActionCable:any;
#Component({
....
})
export class AppComponent implements OnInit{
constructor(){}
ngOnInIt(){
//can access *ActionCable* object here
}
}

Angular2 Beta dependency injection

I have a NavBar Component which loads the QApi Service, the QApi Service loads the UserService, but I get the following error:
EXCEPTION: No provider for UserService! (NavBarComponent -> QApi -> UserService)
Either I simply don't get the concept of dependency injection, I made a stupid error, or this is just way to complicated compared to native development... Thanks for your help.
Here my code:
UserService:
import {Injectable} from 'angular2/core';
//import {User} from '../data-source-mocks/users';
#Injectable()
export class UserService {
public isAuthenticated = true;
}
QApi Service:
import {Injectable} from 'angular2/core';
import {UserService} from '../user/user.service';
#Injectable()
export class QApi {
constructor(private _userService: UserService) {}
}
NavBar Component:
import {Component} from 'angular2/core';
import {QApi} from '../../services/q-api/q-api';
#Component({
selector: 'nav-bar',
template: `Test NavBar`,
providers: [QApi]
})
export class NavBarComponent {
private _isAuthenticated = false;
constructor(private _QApi: QApi) {}
}
EDIT:
First of all: Thanks for alle the great answers each and every single one helped me to understand dependency injection better, especially this article: https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html
I changed my QApi class to this:
import {Injectable, Inject, Injector} from 'angular2/core';
import {UserService} from '../user/user.service';
import {CardService} from '../card/card.service';
#Injectable()
export class QApi {
constructor() {
var _injector = Injector.resolveAndCreate([UserService,
CardService]);
this.userService = _injector.get(UserService);
this.cardService = _injector.get(CardService);
}
}
Now it works like I hoped it would. Cant thank you guys enough!!
Add UserService to the component providers:
#Component({
selector: 'nav-bar',
template: `Test NavBar`,
providers: [QApi, UserService] // <- add UserService here
})
export class NavBarComponent { /* ... */ }
Here are two good articles to better understand Angular2 Dependency Injection:
blog.thoughtram.io: Dependency Injection in Angular2
blog.thoughtram.io: Injecting services in services in Angular 2
In fact both previous responses are true! ;-)
You need to define the services:
Application level. Within the second parameter of the bootstrap function. It contains the list of the providers that are available for the whole application.
bootstrap(App, [UserService, QApi, ...]);
Component level. Within the providers attribute of the Component annotation. In this case, this is only configured for this component and you need to define this for each component where the QApi service.
#Component({
selector: 'nav-bar',
template: `Test NavBar`,
providers: [QApi, UserService]
})
You also mix things. I mean you can put the UserService provider at the application level and QApi at the component level. In fact what is important is that Angular can find providers for all the involved elements in the processing chaining (with dependency injection). They can come from either component level (1st) or application level (2nd).
Hope that it gives you some additional hints following alexpods and MichaelOryl great answers ;-)
Thierry
List the services in your bootstrap call (wherever you are handling that). Something like the following should work:
bootstrap(App, [UserService, QApi, COMMON_DIRECTIVES, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, HTTP_PROVIDERS]);
providers// directives added here are available to all children
Then you will have a single instance of each of those services available to the rest of your application.

Resources