Unable to access jQuery from my views on RoR - ruby-on-rails

I need to access jquery from my views, and I can't figure out how to make rails inject it into the pages. I'm testing for having jquery with the following code:
=render 'nav'
:javascript
if (typeof jQuery != 'undefined') {
// jQuery is loaded => print the version
alert(jQuery.fn.jquery);
} else {
alert("JQuery undefined");
}
It's always been "jquery undefined".
I've tried many things including adding jquery-rails to the Gemfile. Running yarn add jquery.
I tried modifying config/webpack/environment.js to be like this:
const { environment } = require('#rails/webpacker')
const merge = require('webpack-merge')
const webpack = require('webpack')
// Add an additional plugin of your choosing : ProvidePlugin
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
$: 'jquery',
JQuery: 'jquery',
jquery: 'jquery',
'window.Tether': "tether",
Popper: ['popper.js', 'default'], // for Bootstrap 4
})
)
const envConfig = module.exports = environment
const aliasConfig = module.exports = {
resolve: {
alias: {
jquery: 'jquery/src/jquery'
}
}
}
module.exports = merge(envConfig.toWebpackConfig(), aliasConfig)
I added references to jquery also under app/assets/javascripts/application.js
//= require jquery_ujs
//= require jquery
//= require_tree .
//= require bootstrap-sprockets
Here is app/views/layouts/application.html.haml:
<!DOCTYPE html>
%html
%head
%title Imagehost
= csrf_meta_tags
= csp_meta_tag
%meta{"name"=>"viewport", "content"=>"width=device-width", "initial-scale"=>"1", "shrink-to-fit"=>"no"}
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
%body
= yield
There are no error messages on the console.

The ProvidePlugin as you've configured it will require jQuery (when missing) for legacy scripts bundled by Webpack. It does not expose jQuery to the global scope, which explains why it is undefined in your HAML template.
There are a number of ways you can accomplish this, though I'd recommend extending your Webpack configuration using the expose-loader for jQuery. The expose-loader "exposes" variables to the global scope from Webpack.
yarn add expose-loader
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
environment.loaders.prepend('jquery', {
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
},{
loader: 'expose-loader',
options: '$'
}]
})
With the above config added, you should be able to access window.$ and window.jQuery from your HAML templates.

Related

Vue3 doesn't seem to be loaded in Rails 7 + shakapacker app

I created a new project for a shopify app with rails 7 and shakapacker. I want to use Vue components in my .slim files. The problem is that Vue doesn't seem to be loaded in my app, although I don't get any errors.
Here is what I did:
// config/webpack/rules/vue.js
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
new VueLoaderPlugin()
],
resolve: {
extensions: [
'.vue'
]
}
}
// config/webpack/webpack.config.js
const { webpackConfig, merge } = require('shakapacker')
const vueConfig = require('./rules/vue')
module.exports = merge(vueConfig, webpackConfig)
// app/javascript/packs/application.js
import HelloWorld from '../components/HelloWorld'
import { createApp } from 'vue'
const app = createApp({
el: '#app'
})
app.component('helloworld', HelloWorld)
document.addEventListener('DOMContentLoaded', () => {
app
})
// app/javascript/components/HelloWorld.vue
<template>
<h1>Hello world</h1>
</template>
<script>
export default {
name: 'HelloWorld'
}
</script>
/ app/views/layouts/embedded_app.slim
doctype html
html[lang="en"]
head
meta[charset="utf-8"]
- application_name = ShopifyApp.configuration.application_name
title
= application_name
= stylesheet_link_tag "application", "data-turbo-track": "reload"
= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
= csrf_meta_tags
body
#app
.wrapper
main[role="main"]
= yield
= content_tag(:div, nil, id: 'shopify-app-init', data: { api_key: ShopifyApp.configuration.api_key,
shop_origin: #shop_origin || (#current_shopify_session.shop if #current_shopify_session),
host: #host,
debug: Rails.env.development? })
And finally, the view where I just want to display the HelloWorld.vue component:
/ app/views/home/index.slim
helloworld
However, nothing is displayed and I have no errors. I tried to modify the creation of the app in this way, to see if the log appears:
// app/javascript/packs/application.js
import HelloWorld from '../components/HelloWorld'
import { createApp } from 'vue'
const app = createApp({
el: '#app',
created () {
console.log('ok')
}
})
app.component('helloworld', HelloWorld)
document.addEventListener('DOMContentLoaded', () => {
app
})
but then again, I have nothing in console, so I'm not even sure that the app is well rendered. On the other hand, I checked that the DOMContentLoaded event is indeed triggered and it is.
I'm not very comfortable with webpack so I don't know if something is wrong with my configuration, I followed shakapacker's README.
I don't think this is related, but the app is rendered in a Shopify test store via an Ngrok tunnel.
I don't know where to look anymore... Does anyone have an idea?
Thanks in advance
I haven't written any VueJS in a long time, but this is usually what I do in my application.js using React & Shopify Polaris components.
function initialize() {
const rootElement = document.getElementById('app')
const root = createRoot(rootElement);
/* some app bridge code I removed here */
/* react 18 */
root.render(
<BrowserRouter>
/* ... */
</BrowserRouter>
)
}
document.readyState !== 'loading' ? initialize() : document.addEventListener('DOMContentLoaded', () => initialize())
If your <div id="app"> is EMPTY when inspected with browser tools, my first guess would be you're creating an instance, but not actually rendering it in the end.
An application instance won't render anything until its .mount() method is called.
https://vuejs.org/guide/essentials/application.html#mounting-the-app
I would've commented to ask first, but I don't have enough reputation points to do so

How to use jQuery tablesorter with webpacker in rails 6?

Can someone explain what I'm doing wrong here?
Have done yarn add tablesorter and the page loads ok with no errors from webpack, etc. But always get the following:
Uncaught TypeError: $(...).tablesorter is not a function
I get the same error if I just try to manually run .tablesorter() on a table via the console, too.
app/javascript/packs/application.js (in part):
require("#rails/ujs").start()
require("turbolinks").start()
import "controllers"
import 'jquery'
import tablesorter from 'tablesorter/dist/js/jquery.tablesorter'
import 'main'
config/webpack/environment.js:
const { environment } = require('#rails/webpacker')
const coffee = require('./loaders/coffee')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery',
"window.jQuery": "jquery/src/jquery",
Popper: ['popper.js', 'default']
})
)
environment.loaders.prepend('coffee', coffee)
module.exports = environment
app/javascripts/main/index.js:
import 'main/tables.js';
app/javascripts/main/tables.js:
$(document).on('ready turbolinks:load', function() {
if ( $('table.ordered').length > 0 )
{
$('table.ordered').tablesorter({
textExtraction: function(node) {
return $(node).text().replace(/[,$£€]/g,'');
}
})
}
});

Rails 6 + webpack error: Uncaught TypeError: $(...).popover is not a function

I'm starting a new project in rails 6 and it's going to be my first experience with Webpack, I'm having problems using the popover, tooltip, dropdown.
application.js:37 Uncaught TypeError: $(...).dropdown is not a
function
environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.append('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery',
jquery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default'],
Rails: ['#rails/ujs']
})
)
module.exports = environment
application.js
import 'core-js/stable'
import 'regenerator-runtime/runtime'
require("#rails/ujs").start()
require("turbolinks").start()
require("channels")
import 'bootstrap'
import './menu-left.cleanui-custom'
import './menu-right.cleanui-custom'
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)
import '../stylesheets/application'
document.addEventListener("turbolinks:load", () => {
$('[data-toggle=popover-hover]').popover({
trigger: 'hover',
animation: false
});
$("[data-toggle=tooltip]").tooltip({
trigger: 'hover',
animation: false
});
});
$('.dropdown-toggle').dropdown();
Where can the mistake come from? The truth is I'm still pretty lost with webpack.
This worked for me:
config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery',
Popper: ['popper.js', 'default']
})
)
environment.config.merge(
module.exports = {
resolve: {
alias: {
jquery: 'jquery/src/jquery',
}
}
}
)
module.exports = environment
app/javascript/packs/application.js
require("#rails/ujs").start()
require("turbolinks").start()
import "jquery"
import 'bootstrap'
document.addEventListener("turbolinks:load", function() {
$(function () {
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="popover"]').popover()
})
})
Look at my code /config/webpack/environment.js file like below:
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
And /app/javascript/packs/application.js
require("#rails/ujs").start();
require("turbolinks").start();
require("jquery");
require("bootstrap");
By setting these configurations I was able to resolve the error:
Uncaught TypeError: $(…).popover is not a function
For adding bootstrap 4, jQuery and popper.js I used the command below
yarn add bootstrap jquery popper.js

We recently updated from sprockets to webpack, but I am struggling to update the bootstrap-tokenfield library

We recently changed our rails application from sprockets to webpack, and everything seems to have ported over fine, with the exception of bootstrap-tokenfield. On the dev environment server it says that everything has compiled but the tokenfield is not rendering as it should.
I have tried to switch up the location/name of the corresponding css and I have tried appending the JS library to the environment plugins to no avail.
environment.js
// for loading css ...
const merge = require('webpack-merge')
const myCssLoaderOptions = {
modules: true,
sourceMap: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
const CSSLoader = environment.loaders.get('sass').use.find(el => el.loader === 'css-loader')
CSSLoader.options = merge(CSSLoader.options, myCssLoaderOptions)
const webpack = require('webpack');
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default']
}));
module.exports = environment
application.js
import Turbolinks from 'turbolinks';
import 'bootstrap/dist/js/bootstrap';
import 'trix';
import 'chosen-js';
import '#coreui/coreui';
import 'jquery-ui';
import 'bootstrap-tokenfield'
Rails.start();
Turbolinks.start();
$(document).ready(function(){
$('form').on('click', '.remove_record', function(event) {
$(this).prev('input[type=hidden]').val('1');
$(this).closest('tr').hide();
return event.preventDefault();
});
$('form').on('click', '.add_fields', function(event) {
var regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.fields').append($(this).data('fields').replace(regexp, time));
return event.preventDefault();
});
});
$(document).on('click', "tr[data-link]", function(){
window.location = $(this).data("link")
});
$(document).on('turbolinks:load', function() {
$('.chosen-select').chosen({
disable_search_threshold: 10,
width: '140px'
})
$('.chosen-select-form').chosen({
disable_search_threshold: 7,
width: '100%'
})
$('[data-toggle="tooltip"]').tooltip()
})
application.scss (still being compiled by sprockets)
/*
*= require_tree .
*= require chosen
*= require jquery-ui
*= require bootstrap-tokenfield
//*= require trix
*
*/
// "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables"
#import "bootstrap";
#import "font-awesome";
#import '#coreui/coreui/dist/css/coreui.min';
I expect that the views with tokenfield built in render a tokenfield input, but they currently just show a regular text input.
I just included the jquery ui and bootstrap tokenfield libraries directly on the layout.html.erb page and it fixed it.

UI-view not changed

I making application in Ruby on Rails and using AngularJS.
My application.js file is
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require angular.min
//= require angular-ui-router.min
var app = angular.module("railsApp", ['ui.router']).config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html'
})
.state('about', {
url: 'about',
templateUrl: 'about.html'
});
$urlRouterProvider.otherwise('/');
});
app.controller("mainCtrl", function($scope) {
$scope.helloMsg = "Hello from test application";
});
index page
<h1>Welcome#index</h1>
<p>Find me in app/views/welcome/index.html.erb</p>
{{helloMsg}}<br>
<ui-view></ui-view>
<a ui-sref="about">about</a>
when index page loaded I see message "Hello from test application" and into <ui-view></ui-view> substituted template content, but I clicked about link new template is not loading and url not changed to /about. what is the problem? Thanks and Sorry for my english
Please try this will fix your URL issue and renders the requested views.You have to give perfect URL
so that view will be mathced perfactly.
var app = angular.module("railsApp", ['ui.router']).config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html'
})
.state('/about', {
url: 'about',
templateUrl: 'about.html'
});
$urlRouterProvider.otherwise('/');
});
as per the ui router readme, try to change url: 'about' tourl: '/about'

Resources