Cliff Hudson
Cliff Hudson

Reputation: 321

Material 2 attributes in Angular 4 aren't working with webpack, ASP.NET

I'm trying to get Material 2 to work with Angular 4.4.6 using webpack in an ASP.NET Core 2 web application. I get no errors but I currently get no styling and the mat-button attribute has no effect on the output DOM.

I have done the following:

  1. Environment is as follows:

    • Visual Studio (Professional) 2017 version 15.4.0
    • ASP.NET Core 2 web application with Angular, from VS template
  2. Update @angular packages to ^4.4.6 in NPM and restore packages

    "@angular/animations": "^4.4.6",
    "@angular/common": "^4.4.6",
    "@angular/compiler": "^4.4.6",
    "@angular/compiler-cli": "^4.4.6",
    "@angular/core": "^4.4.6",
    "@angular/forms": "^4.4.6",
    "@angular/http": "^4.4.6",
    "@angular/platform-browser": "^4.4.6",
    "@angular/platform-browser-dynamic": "^4.4.6",
    "@angular/platform-server": "^4.4.6",
    "@angular/router": "^4.4.6",
    
  3. Per the Material guide, run the following command in the project directory:

    npm install --save @angular/material @angular/cdk
    
  4. Update webpack.config.vendor.js to add the following lines to the treeShakableModules array, just after '@angular/router':

    '@angular/material',
    '@angular/material/prebuilt-themes/deeppurple-amber.css',
    
  5. In app.module.browser.ts, import the module:

    import { MatButtonModule } from '@angular/material';
    
    @NgModule({
        bootstrap: [ AppComponent ],
        imports: [
          BrowserModule,
          MatButtonModule,
            AppModuleShared
        ],
        providers: [
            { provide: 'BASE_URL', useFactory: getBaseUrl }
        ]
    })
    
  6. In home.component.html, add the following line at the end of the file:

    <button mat-raised-button>This is a button</button>
    
  7. From the project directory, run webpack to update the vendor files:

    webpack --config webpack.config.vendor.js
    
  8. Build and run the application

  9. Observe the home page button is not styled. There are no errors in the console suggesting missing styles or invalid attributes.

I have the following configuration:

Verified the styles do exist, as specifying class="mat-raised-button" on the button has an effect (though it does not look like the raised button) it does change the interior styling of the button.

I note that the attribute does not appear to have any effect on the styling or content of the output HTML (versus what I see when inspecting the elements on the guide website), suggesting that something has gone wrong with the setup of the module, but I can't for the life of me figure out what that might be.

EDIT: By request, here is the webpack.config.vendor.js up to the boilerplate:

const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const merge = require('webpack-merge');
const treeShakableModules = [
    '@angular/animations',
    '@angular/common',
    '@angular/compiler',
    '@angular/core',
    '@angular/forms',
    '@angular/http',
    '@angular/platform-browser',
    '@angular/platform-browser-dynamic',
    '@angular/router',
    'zone.js',
];
const nonTreeShakableModules = [
    '@angular/cdk',
    '@angular/material',
    '@angular/material/button',
    '@angular/material/prebuilt-themes/deeppurple-amber.css',
    'bootstrap',
    'bootstrap/dist/css/bootstrap.css',
    'es6-promise',
    'es6-shim',
    'event-source-polyfill',
    'jquery',
]; 

const allModules = treeShakableModules.concat(nonTreeShakableModules);

module.exports = (env) => {
    const extractCSS = new ExtractTextPlugin('vendor.css');
    const isDevBuild = !(env && env.prod);
    const sharedConfig = {
        stats: { modules: false },
        resolve: { extensions: [ '.js' ] },
        module: {
            rules: [
                { test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: 'url-loader?limit=100000' }
            ]
        },
        output: {
            publicPath: 'dist/',
            filename: '[name].js',
            library: '[name]_[hash]'
        },
        plugins: [
            new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), //     Maps these identifiers to the jQuery package (because Bootstrap expects it to be     a global variable)
            new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/,     path.join(__dirname, './ClientApp')), // Workaround for     https://github.com/angular/angular/issues/11580
            new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/,     path.join(__dirname, './ClientApp')), // Workaround for     https://github.com/angular/angular/issues/14898
            new webpack.IgnorePlugin(/^vertx$/) // Workaround for     https://github.com/stefanpenner/es6-promise/issues/100
        ]
    };

... boilerplate follows this ...

Upvotes: 1

Views: 471

Answers (2)

Cliff Hudson
Cliff Hudson

Reputation: 321

So somewhat counterintuitively, the solution requires that the module importing be done in app.module.shared.ts, not app.module.browser.ts. If you are using the default Angular template, use the same steps as above, except for step 5, do the following:

Edit app.module.shared.ts to add the MatButtonModule module as an import, as follows:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';

import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
import { CounterComponent } from './components/counter/counter.component';

@NgModule({
    declarations: [
        AppComponent,
        NavMenuComponent,
        CounterComponent,
        FetchDataComponent,
        HomeComponent
    ],
    imports: [
        CommonModule,
        HttpModule,
        FormsModule,
        MatButtonModule,
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: 'counter', component: CounterComponent },
            { path: 'fetch-data', component: FetchDataComponent },
            { path: '**', redirectTo: 'home' }
        ])
    ]
})
export class AppModuleShared {
}

Note also it is not necessary to add @angular/cdk or @angular/material/button to the modules list in webpack.config.vendor.js. It is sufficient to add the ones described in the guide.

See: https://github.com/angular/material2/issues/7997

Upvotes: 1

esso
esso

Reputation: 125

According to official docs Here You've to Import theming to your Global style file this is as simple as including one line in your styles.css file:

@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';

or Alternatively, you can just reference the file directly. Available pre-built themes:

  1. deeppurple-amber.css
  2. indigo-pink.css
  3. pink-bluegrey.css
  4. purple-green.css

Upvotes: 0

Related Questions