I have a fresh Laravel 5.8 installation and I would like to include the js modules from MDBootstrap.
In my bootstrap.js file I have:
require('./mdb/modules');
The ./mdb/modules.js file has:
exports.modules = [
'./js/_intro-mdb-pro.js',
'./js/scrolling-navbar.js',
'./js/vendor/jquery.easing.js',
'./js/vendor/velocity.js',
'./js/vendor/chart.js',
'./js/vendor/wow.js',
... 30 more
];
The compilation works ok, but of course, it doesn't take any effect from these modules include.
I don't know how to include all of them at once as they are not looking like a regular module so I can import like 'import * from 'my-module'
I also tried the ES6 way:
import * as MDBootstrap from './mdb/modules';
but I got the same result: successful compilation without including them into the compiled js file.
The content of these 'modules' doesn't seem to look like a normal module where we export default {} or some other functions or variables. It looks like:
//mdb/js/scrolling-navbar.js
"use strict";
(function ($) {
var SCROLLING_NAVBAR_OFFSET_TOP = 50;
$(window).on('scroll', function () {
var $navbar = $('.navbar');
if ($navbar.length) {
if ($navbar.offset().top > SCROLLING_NAVBAR_OFFSET_TOP) {
$('.scrolling-navbar').addClass('top-nav-collapse');
} else {
$('.scrolling-navbar').removeClass('top-nav-collapse');
}
}
});
})(jQuery);
Even 'exports.modules = [..]' is not familiar to me. I know about 'module.export = ...' but this 'exports' looks like it's a Node.js object.
I know there's also another method to include the dist version of the plugin. I also tried it, but I got some errors: 'Identifier '_classCallCheck' has already been declared'. I looked deeper and I found that actually many of those files are declaring the '_classCallCheck' function and of course that it a redeclare error. Maybe I can refer to this particular error directly to them (MDBootstrap).
So here I am, trying to include and use these modules/files in my Laravel project without success. Any help is appreciated.
Related
I'm trying to import a file into TypeScript that's basically just a js file that you'd put into a tag. I've tried a few different things.
// global.d.ts
declare module 'myfile.js'
Inside of the react file:
// component.tsx
import { foo } from '../lib/myFile.js' // This is saying it is not a module
Inside of the js file, it looks like this a few times so not sure how I need to reference the file:
(function( something ) {
something.Foo = function (){}
}(window.something = window.something || {}));
Any thoughts on how I could use this file? Do I need to go through and declare typings for everything in it?
EDIT: I've added allowJS to my tsconfig but it still doesn't work.
You can only import what is exported from the file.
If your file contains only immediately invoked functions, or top level code, you only need to import the file itself like this:
import '../lib/myFile.js'
This is a little weird, however. I would suggest wrapping everything with a function and exporting then importing that function instead.
We are trying a POC of adding Typescript and Webpack to our Angularjs project.
I am able to get my webpack bundle to generate, however at runtime the program cannot find the various functions in my validator.js. Can you please offer some advice?
login-view.components.ts
declare var findFormNode: any; //function in validator.js
//LogInUser
self.login = function ($event, command) {
if (findFormNode($event.target.id)) {
...
}
}
main.ts is importing the file
import "./../../../CommonStaticFiles/include/js/Validators.js";
bundle.js
eval("/* WEBPACK VAR INJECTION */(function($) {/*\r\n\r\n VALIDATORS\r\n\r\n ... n\n\nfunction findFormNode(
error
ReferenceError: findFormNode is not defined
at LoginController.self.login (login-view.component.ts:28)
at fn (eval at compile (angular.js:NaN), <anonymous>:4:267)
at callback (angular.js:29019)
In order for your functions to be properly imported, there are few things that you have to make sure of.
First, make sure you are exporting your functions correctly. Here's an example of how to export a function from Validator.js:
export const validateFunc1 = ():void => {};
Next, you have to make sure you are using proper import syntax. In order to import the function above, you would do the following:
import {validateFunc1} from "./../../../CommonStaticFiles/include/js/Validators.js";
Alternatively, if you want to import all exported functions at once, then you can use this syntax:
import * as validatorFuncs from "./../../../CommonStaticFiles/include/js/Validators.js";
Lastly, check that the location of Validators.js is correct. It's a common mistake to be looking in the wrong directory. Your code editor can usually help you find the right path to use.
I have following structure for Javascript in my Rails 6 app using Webpacker.
app/javascript
+ packs
- application.js
+ custom
- hello.js
Below shown is the content in the above mentioned JS files
app/javascript/custom/hello.js
export function greet(name) {
console.log("Hello, " + name);
}
app/javascript/packs/application.js
require("#rails/ujs").start()
require("jquery")
require("bootstrap")
import greet from '../custom/hello'
config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default']
})
)
module.exports = environment
Now in my Rails view I am trying to use the imported function greet like shown below
app/views/welcome/index.html.haml
- name = 'Jignesh'
:javascript
var name = "#{name}"
greet(name)
When I load the view I am seeing ReferenceError: greet is not defined error in browser's console.
I tried to search for a solution to this problem and found many resources on web but none turned out to help me. At last when I was drafting this question in the suggestions I found How to execute custom javascript functions in Rails 6 which indeed is close to my need however the solution shows a workaround but I am looking for a proper solution for the need because I have many views which needs to pass data from Rails view to JS functions to be moved custom files under app/javascript/custom folder.
Also I would highly appreciate if anybody can help me understand the cause behind the ReferenceError I am encountering.
Note:
I am not well-versed in Javascript development in Node realm and also new to Webpacker, Webpack, Javascript's modules, import, export, require syntax etc so please bear with me if you find anything silly in what I am asking. I have landed up in above situation while trying to upgrade an existing Rails app to use version 6.
Webpack does not make modules available to the global scope by default. That said, there are a few ways for you to pass information from Ruby to JavaScript outside of an AJAX request:
window.greet = function() { ... } and calling the function from the view as you have suggested is an option. I don't like have to code side effects in a lot of places so it's my least favorite.
You could look at using expose-loader. This would mean customizing your webpack config to "expose" selected functions from selected modules to the global scope. It could work well for a handful of cases but would get tedious for many use cases.
Export selected functions from your entrypoint(s) and configure webpack to package your bundle as a library. This is my favorite approach if you prefer to call global functions from the view. I've written about this approach specifically for Webpacker on my blog.
// app/javascript/packs/application.js
export * from '../myGlobalFunctions'
// config/webpack/environment.js
environment.config.merge({
output: {
// Makes exports from entry packs available to global scope, e.g.
// Packs.application.myFunction
library: ['Packs', '[name]'],
libraryTarget: 'var'
},
})
// app/views/welcome/index.html.haml
:javascript
Packs.application.greet("#{name}")
Take a different approach altogether and attach Ruby variables to a global object in your controller, such as with the gon gem. Assuming you setup the gem per the instructions, the gon object would be available both as Ruby object which you can mutate server-side and in your JavaScript code as a global variable to read from. You might need to come up with some other way to selectively call the greet function, such as with a DOM query for a particular selector that's only rendered on the given page or for a given url.
# welcome_controller.rb
def index
gon.name = 'My name'
end
// app/javascript/someInitializer.js
window.addEventListener('DOMContentLoaded', function() {
if (window.location.match(/posts/)) {
greet(window.gon.name)
}
})
#rossta Thanks a lot for your elaborate answer. It definitely should be hihghly helpful to the viewers of this post.
Your 1st suggestion I found while searching for solution to my problem and I did referenced it in my question. Like you I also don't like it because it is sort of a workaround.
Your 2nd and 3rd suggestions, honestly speaking went top of my head perhaps because I am novice to the concepts of Webpack.
Your 4th approach sounds more practical to me and as a matter of fact, after posting my question yesterday, along similar lines I tried out something and which did worked. I am sharing the solution below for reference
app/javascript/custom/hello.js
function greet(name) {
console.log("Hello, " + name)
}
export { greet }
app/javascript/packs/application.js
require("#rails/ujs").start()
require("bootstrap")
Note that in above file I removed require("jquery"). That's because it has already been made globally available in /config/webpack/environment.js through ProvidePlugin (please refer the code in my question). Thus requiring them in this file is not needed. I found this out while going through
"Option 4: Adding Javascript to environment.js" in http://blog.blackninjadojo.com/ruby/rails/2019/03/01/webpack-webpacker-and-modules-oh-my-how-to-add-javascript-to-ruby-on-rails.html
app/views/welcome/index.html.haml
- first_name = 'Jignesh'
- last_name = 'Gohel'
= hidden_field_tag('name', nil, "data": { firstName: first_name, lastName: last_name }.to_json)
Note: The idea for "data" attribute got from https://github.com/rails/webpacker/blob/master/docs/props.md
app/javascript/custom/welcome_page.js
import { greet } from './hello'
function nameField() {
return $('#name')
}
function greetUser() {
var nameData = nameField().attr('data')
//console.log(nameData)
//console.log(typeof(nameData))
var nameJson = $.parseJSON(nameData)
var name = nameJson.firstName + nameJson.lastName
greet(name)
}
export { greetUser }
app/javascript/packs/welcome.js
import { greetUser } from '../custom/welcome_page'
greetUser()
Note: The idea for a separate pack I found while going through https://blog.capsens.eu/how-to-write-javascript-in-rails-6-webpacker-yarn-and-sprockets-cdf990387463
under section "Do not try to use Webpack as you would use Sprockets!" (quoting the paragraph for quick view)
So how would you make a button trigger a JS action? From a pack, you add a behavior to an HTML element. You can do that using vanilla JS, JQuery, StimulusJS, you name it.
Also the information in https://prathamesh.tech/2019/09/24/mastering-packs-in-webpacker/ helped in guiding me to solve my problem.
Then updated app/views/welcome/index.html.haml by adding following at the bottom
= javascript_pack_tag("welcome")
Finally reloaded the page and the webpacker compiled all the packs and I could see the greeting in console with the name in the view.
I hope this helps someone having a similar need like mine.
I have put my js files eva.min.js/feather.min.js and so on in vendor dir, then I imported them in ember-cli-build.js app.import('vendor/eva.min.js'). But how to use it?
I tried something like import eva from 'eva'/'eva.min'/'eva.min.js' or import Eva from 'eva'; and so on, but it doesn't work.
app.import('vendor/eva.min.js');
app.import('vendor/bootstrap.min.js');
app.import('vendor/feather.min.js');
app.import('vendor/popper.min.js');
app.import('vendor/jquery-slim.min.js');
app.import('vendor/swipe.js');
import Swipe from 'swipe';
Console usually gives me the could not find the module error.
And I don't have a deep background in programming, so I would highly appreciate if you explained the problem as simple as possible.
UPD: I found all js code as npm package (it happens that the js files weren't third-party)
https://www.npmjs.com/package/feather
https://www.npmjs.com/package/popper.js
https://www.npmjs.com/package/jquery-slim
https://www.npmjs.com/package/swipe
https://www.npmjs.com/package/bootstrap
https://www.npmjs.com/package/eva-icons
But all your responses were helpful. Anyway in the near future I expect to use third-party libraries.
A quick way is to use scriptjs and it allows you to load any javascript into your component in the following way: (I am using Yammer as an example)
import $scriptjs from 'scriptjs';
componentDidUpdate() {
//script loader
setTimeout(function(){
$scriptjs('https://c64.assets-yammer.com/assets/platform_embed.js',
() => {
window.yam.connect.embedFeed(YammerHelper.loadComments());
});
}, 1000);
}
You should get the idea how to consume it. Check their docs with lots of examples.
This is not the best solution. But one way of using the third party js is,
1) say you have a function in your js file vendor/third-party.js
someFunction = function (element) {
...
console.log("works")
};
2) Then import it in your ember-cli-build.js
...
app.import('vendor/third-party.js');
...
3) After importing restart your server.
Use the function directly in your controller/component as
window["someFunction"]
Unless the JavaScript library being used explicitly supports the import X from 'y' syntax then when you import in the build using the app.import syntax you just use it in your app just as the plugin documentation describes.
So for Swipe you would do the following.
Based on this documentation: https://github.com/thebird/Swipe
// ember-cli-build.js
app.import('myswipe.js`);
// component.js
/* global Swipe */ // This silences the linter from throwing errors...
classNames: ['swipe'],
didInsertElement() {
this._swipe = Swipe(this.element, {
option1: option1
});
}
// component.hbs
<div class='swipe-wrap'>
{{yield}}
</div>
This codes creates a component to control your swipe plugin.
This code would create a swipe object and isolate it to the component.
Again when you use the app.import you are just loading the library on boot. The library does whatever it says it will do in the docs. Sometimes they register a global object, sometimes they dont.
I am including my js file into my main html file like so
<script type="text/babel" src="js/scripts.js"></script>
Then I call one of my functions like so
<div class="allButton" id="completeAll" onclick="showAll('completeColumn');">Show All (...)</div>
the function looks like this
function showAll(column) {
$('div[id^='+column+']').removeClass('hide');
};
When I click the button(div) I get this error
Uncaught ReferenceError: showAll is not defined
I am using the text/babel as my script type because the file contains React JS stuff.
I have no idea why I simply cannot call my function. I am extremely new to ReactJS and Babel. (note: I am not using npm/gulp due to limitations)
Any help and/or advice would be appreciated
If you just define your function as follows you will be able to call it within the HTML.
window.showAll = function showAll(column) {
// your code here...
};
You have not exported your showAll function. When you transpile a JS/JSX file with Babel and bundle it to a scripts.js file (using Browserify or similar utilities), you must make sure to export your module (which tells your bundler to package it into your bundled file).
Your code should look like this:
var showAll = function(column) {
$('div[id^='+column+']').removeClass('hide');
};
module.exports = showAll;
This tells your bundler that your showAll method needs to be exported and available to other referenced namespaces.