Rashad Ibrahimov
Rashad Ibrahimov

Reputation: 3309

TypeError: element.summernote is not a function

I'm working on project based on Angular, Webpack, etc. And I've faced to very interesting issue when I wanted to use angular-summernote

It doesn't work, and gives me an error "TypeError: element.summernote is not a function". It works normally if adding libraries as script tags, without any build tool, but with Webpack it doesn't.

So, let's look at files and configs

webpack.config.js

let webpack = require('webpack');
let path = require('path');

module.exports = {

    entry: {
        bundle: [
            './app/app.js'
        ]
    },
    output: {
        path: path.join(__dirname, './public'),
        filename: '[name].js',
    },
    resolve: {
        root: __dirname,
        extensions: ['', '.js'],
        modulesDirectories: [
            'node_modules',
            'app'
        ],
    },
    externals: {

    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery'
        })
    ],
    module: {
        loaders: [
            {
                loader: 'babel-loader',
                query: {
                    presets: ['es2015']
                },
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/
            }
        ]
    }

};

app/app.js

// Load libs
import angular from 'angular';
import ngRoute from 'angular-route';
import summernote from 'summernote';
import ngSummernote from 'angular-summernote/dist/angular-summernote.js';

// App
angular.module('app', [ngRoute, 'summernote'])

.config(function($routeProvider) {

    // Router
    $routeProvider

        .when('/', {
            template: '<summernote></summernote>'
        });
});

I've found github issue, but it still has Open status.

I made some debug, checked "link" method of "summernote" directive, and logged "element" to console, it's proto object doesn't contain any jquery methods including "summernote" method. Why? And how to make it work?

Upvotes: 4

Views: 5371

Answers (1)

Rashad Ibrahimov
Rashad Ibrahimov

Reputation: 3309

It seems like jquery is used on demand and not loaded before other scripts, so it doesn't expose global variable jQuery, and doesn't attach appropriate methods to elements.

The following configuration solves this problem

webpack.config.js

let webpack = require('webpack');
let path = require('path');

module.exports = {

    entry: {
        bundle: [
            // We tell webpack to add jquery as script tag before app script
            // It will expose global variable jQuery and init jquery methods
            'script!jquery/dist/jquery.min.js',

            './app/app.js'
        ]
    },
    output: {
        path: path.join(__dirname, './public'),
        filename: '[name].js',
    },
    resolve: {
        root: __dirname,
        extensions: ['', '.js'],
        modulesDirectories: [
            'node_modules',
            'app'
        ],
    },
    externals: {
        // This mean that require('jquery') will refer to global var jQuery
        'jquery': 'jQuery' 
    },
    plugins: [
        // ProvidePlugin helps to recognize $ and jQuery words in code
        // And replace it with require('jquery')
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery'
        })
    ],
    module: {
        loaders: [
            {
                loader: 'babel-loader',
                query: {
                    presets: ['es2015']
                },
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/
            }
        ]
    }

};

Hope it will be useful to clarify how webpack works. And please share your thoughts and comments if I missed something.

Upvotes: 3

Related Questions