Uncaught Error: rails-ujs has already been loaded when calling a Stimulus controller on a field in simple_form - ruby-on-rails-6

Hello everyone :) I'm building an application with Rails 6.1.6.
I am using select2 with simple_form like this:
<%= f.association :events, input_html: { data: { controller: 'select2' } } %>
My Stimulus controller is the following:
import { Controller } from "#hotwired/stimulus"
import $ from 'jquery'
import 'select2'
import "select2/dist/css/select2.min.css"
export default class extends Controller {
connect() {
const matchEvent = (params, data) => {
if ($.trim(params.term) === '') {
return data;
}
if (typeof data.text === 'undefined') {
return null;
}
if (data.text.toUpperCase().indexOf(params.term.toUpperCase()) > -1) {
var modifiedData = $.extend({}, data, true);
modifiedData.text += ' ';
return modifiedData;
}
return null;
};
$(this.element).select2({
closeOnSelect: false,
placeholder: "Select an event from our Database",
minimumInputLength: 3,
selectOnClose: true,
allowClear: true,
matcher: matchEvent
})
}
}
For completeness, this is how my application.js looks like:
import Rails from "#rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "#rails/activestorage"
import "channels"
Rails.start()
Turbolinks.start()
ActiveStorage.start()
import "controllers"
import "bootstrap"
While, in the head of my application.html.erb, I have:
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>
Any time I log in the application and go to the page when I have this simple_form, I see this error message in the console:
Uncaught Error: rails-ujs has already been loaded!
Which points to a conflict between my application.js calling Rails.start() and something inside node_module.
Ever seen anything like this?
Just to be clear, the form works perfectly but at each first visit to the page I see an annoying inline text-field beside the label and, moreover, this issue made my application lag in the other pages. Only a refresh of the browser fixes it.
What am I missing?
Thanks a lot for your help!
EDIT:
Issue fixed! It was showing up only when navigating through the app by links (not when typing the path in the address bar of the browser) so the problem was with turbolinks reload. By adding data: { turbolinks: false } to the link of the page, the issue has disappeared!

Related

flatpickr via rails importmap not being generated

Attempting to use flatpickr as a UI for setting a date field with Rails 7.0.1 and ruby 3.1. When clicking on the input field, the expected 2 months of calendars is not rendered & in fact, nothing is registered in the browser network tab.
After bin/importmap pin flatpickr rails pinned the library to the cdn in the importmap.rb file:
pin "flatpickr", to: "https://ga.jspm.io/npm:flatpickr#4.6.9/dist/flatpickr.js"
application.js has the initially generated import "controllers".
flatpickr_controller.rb was created in the javascript/controllers directory with
import { Controller } from "#hotwired/stimulus"
import flatpickr from "flatpickr"
export default class extends Controller {
connect() {
this.config = {
enableTime: false,
dateFormat: 'Y-m-d',
}
}
}
The view partial invokes:
<%= form_with model: promo do |f| %>
<%= f.text_field :date_from, placeholder: t(".select"), data: { controller: "flatpickr" } %>
<% end %>
while the controller sets
#promos = Promo.up_comings(60)
#promo = Promo.new
#next_promo = Promo.next
#dates_to_disable = #promos.pluck(:date_from)
Why is the calendar not rendering?
I am also confused as to where to place the different flatpickr options: in the controller, or straight into the form date element.
The issue is related to support for Stimulus 3. Pin as follows:
bin/importmap pin stimulus-flatpickr#beta
Also reference some css source, such as to the latest version
<link rel="stylesheet" href="https://ga.jspm.io/npm:flatpickr#4.6.9/dist/flatpickr.min.css">
otherwise the input field will be deemed as readonly...

Next.js dynamic import with custom loading component: "Warning: Expected server HTML to contain a matching <em> in <div>."

I have a next.js page with dynamic imports, which worked well until now,
but since I started using the custom loading components I get the warning
Warning: Expected server HTML to contain a matching <em> in <div>.
What can I do to avoid this warning ?
Here a reduced example:
// pages/index.tsx:
import React from 'react';
import dynamic from 'next/dynamic';
import { LoadingComponent } from '../src/LoadingComponent';
// -- The custom loading fallback component
const loadingFallback = { loading: LoadingComponent };
// -- The dynamically loaded component
const DynamicallyLoadedComponent = dynamic(
() => import('../src/DynamicallyLoadedComponent'),
loadingFallback
);
// -- The main component
function Main(){
return <DynamicallyLoadedComponent />;
}
export default Main;
// src/DynamicallyLoadedComponent.tsx:
export default function DynamicallyLoadedComponent(){
return <div>ready loaded, final page content.</div>;
};
// src/LoadingComponent.tsx:
export const LoadingComponent = () => {
return <em>... loading ...</em>;
}
Apparently you can not extract the part { loading: LoadingComponent } into a variable, so it has to be written
inline, e.g.:
const DynamicallyLoadedComponent = dynamic(
() => import('../src/DynamicallyLoadedComponent'),
{ loading: LoadingComponent } // <-- needs to be written like this, a variable can't be used
);
Maybe this is because Next.js analyses the code in a kind of "pre-compiling" step and expects to find exactly this pattern (?).
Probably this is the same requirement as mentioned under Basic usage regarding the dynamic import itself:
Note: In import('path/to/component'), the path must be explicitly written.
It can't be a template string nor a variable.
Furthermore the import() has to be inside the dynamic() call for Next.js to be able to match
webpack bundles / module ids to the specific dynamic() call and preload them before rendering.
dynamic() can't be used inside of React rendering as it needs to be marked in the top level
of the module for preloading to work, similar to React.lazy.

Why is my Stimulus JS controller firing twice?

So, I have a Rails application with webpacker, vue, turbolinks and stimulus js installed.
The problem that I am having is that even though the controller is only imported once and even if I temporarily disable turbolinks the initialize() funcition along with the connect() one get called twice.
This only happens if I do a refresh (i.e. not when I visit the page for the first time, but only if I perform a page reload).
Strangely enough the disconnect() is only getting called once (when I do leave the page)
This sucks because I need to modify the DOM in the initialize, so I get elements added twice.
Does someone have any clue to what's causing this, and / or a solution?
EDIT: application.js as requested
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
import "stylesheets"
import "controllers"
import "components"
components/index.js
import Vue from 'vue/dist/vue.esm'
import BootstrapVue from 'bootstrap-vue'
import TurbolinksAdapter from 'vue-turbolinks'
Vue.use(BootstrapVue)
Vue.use(TurbolinksAdapter)
const components = {}
const context = require.context("components", true, /_component\.vue$/)
context.keys().forEach(filename => {
const component_name = filename.replace(/^.*[\\\/]/, '').replace(/_component\.vue$/, '')
const component = context(filename).default
components[component_name] = component
})
document.addEventListener('turbolinks:load', () => {
const app = new Vue({
el: '#vueapp',
mounted() {
let input = document.querySelector('[autofocus]');
if (input) {
input.focus()
}
},
components: { ...components }
})
})
controllers/index.js
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"
const application = Application.start()
const context = require.context("controllers", true, /_controller\.js$/)
application.load(definitionsFromContext(context))
in each and every file, if I console.log it gets logged only once...
only in the stimulus controller initialize or connect gets printed twice
this happens only when I reload the page, not when I first visit it.
This is probably due to Turbolinks. When navigating to a new page, Turbolinks first presents a cached version of the page (first stimulus connect) and afterwards replaces the body with the actual requested version of the page (second stimulus connect). See here for more details:
https://mrcodebot.com/turbolinks-calls-stimulus-connect-twice/

Hide Ionic TabBar on specific subpages (IONIC 3)

I want to hide my tabbar on multiple specific pages. My main focus is to hide it on my Login page, Register page, and a comment page. I have tried tabsHideOnSubPages: true, but when i do this my UserProfile page
(which is a subpage) hides the tabbar. The tabbar must also be visible on the UserProfile page but then again not on my previous mentioned subpages (login, register etc..).
I am currently using Ionic Framework : ionic-angular 3.2.0
Does anyone know how i can fix this?
I can give you a quick hotfix for that.
Copy this Code into your .ts page file.
The function will execute when the page is loaded.
If you want to hide the tabbar then do this line of code:
tabs[key].style.display = 'none';
If you want to show it use this code by simply changing 'none' it to 'flex'.
tabs[key].style.display = 'flex';
This code is an angular function wich basicly means it executes when page is loaded.
ngAfterViewInit()
Full code:
ngAfterViewInit() {
let tabs = document.querySelectorAll('.show-tabbar');
if (tabs !== null) {
Object.keys(tabs).map((key) => {
tabs[key].style.display = 'none';
});
}
}
You can also use this code to show the tabbar again if you leave the page.
ionViewWillLeave() {
let tabs = document.querySelectorAll('.show-tabbar');
if (tabs !== null) {
Object.keys(tabs).map((key) => {
tabs[key].style.display = 'flex';
});
}
}
Hope this helped you.
You can try this.
Just put tabsHideOnSubPages in your config like this:
#NgModule({
declarations: [ MyApp ],
imports: [
IonicModule.forRoot(MyApp, {
tabsHideOnSubPages: true,
}, {}
)],
bootstrap: [IonicApp],
entryComponents: [ MyApp ],
providers: []
})

Angular 2 Router strange null call

Problem
Im loading some menu items from the Wordpress Rest API, then navigate to the page/:id with the correct id of the wordpress page. Everything works fine except of that:
Early when my page is loading I get this null call in the network section of the chrome developer. This is locally, on my server its also a 404 NOT FOUND.
Setup
Angular 2 + Typescript (Angular 2 RC2, Router 3.0.0-alpha.6)
Wordpress REST API
Code
Template
<header></header>
<router-outlet></router-outlet>
<footer></footer>
Routing
export const routes: RouterConfig = [
{ path: '/page/:id', component: PageComponent },
{ path: '/page/home', component: PageComponent, index: true }
];
Header.ts
this.myService.getNavigation()
.subscribe(
menuItems => {
this.menuItems = menuItems;
this.router.navigate(['/page', this.menuItems[0].title]);
},
error => this.errorMessage = <any>error);
Main.ts
bootstrap(AppComponent, [
...APP_ROUTER_PROVIDERS,
...HTTP_PROVIDERS,
...ROUTER_PROVIDERS,
...ENV_PROVIDERS,
{ provide: LocationStrategy, useClass: HashLocationStrategy }
])
Assumption
I guess it has something to do with my routing setup. When I comment out the <router-outlet> it does not happen, everything else works good.
Question
What is this strange call at /null and how can I avoid it?
I guess you have somewhere <img [attr.src]="var"> or similar.

Resources