window.autoInit in Rails using material-components-web and webpacker - ruby-on-rails

I'm using Rails 5.1.4 with the code below. I have confirmed that the material.js file is being processed and the material-components-web module is downloaded and discovered.
Why is mdc undefined when calling window.mdc.autoInit()?
// app/javascript/packs/material.js
import 'material-components-web'
// app/views/layouts/application.html.eeb
<html>
<head>
<%= javascript_pack_tag 'material' %>
</head>
<body>
<script>window.mdc.autoInit();</script>
</body>
</html>
I have tried
importing #material/auto-init separately.
Putting the autoInit call inside an onload
Adding a console.dir(window)/console.dir(this) inside pack file. this is not window inside the the pack file and the exports aren't being attached to this

To make material-components-web work with Rails I did
// app/javascript/packs/material.js
import * as mdc from 'material-components-web'
// for accessing it as a window object
window.mdc = mdc
And then I made sure window.mdc.autoInit() was called at the end of the body

Related

How to call a javascript function inside a rails view?

I did just a upgrade from RAILS 5 to RAILS 6 and I see that all rails views are not able to call a javascript function as before in RAILS 5.
I have an external javascript file located under
app/javascript/packs/station.js
This is is embeded in in app/views/layouts/application.html.erb as
<%= javascript_pack_tag 'station' %>
This is the code how I call the javascrpt function from html.erb file :
<%= text_field_tag(:station_text_field, ... ,
onkeyup: "javascript: request_stations(); ") %>
When I try to call a function thats is part of the station.js then I get an error in the browser developmer view: ReferenceError: request_stations is not defined
But I can also see in the brwoser view, under Debugger :
Webpack / app/javascript / packs / station.js
and the javascript function I want to call.
So it seems that this script was loaded by the browser.
In contrast, when I just copy and paste these few lines that represent this javascript function direct into the template view file (...html.erb), something like :
<script>
function request_stations ()
{
alert("calling request_stations");
};
</script>
then - it works as expected !
By default, variables/functions defined inside JavaScript files that are packed by Webpacker will not be available globally.
This is a good thing, because it prevents global naming conflicts. Generally speaking, you don't want to reference javascript functions/variables from your view. You instead want to write JavaScript in a way that attaches functionality to DOM nodes using their id or other attributes.
Here is a basic example based on the code you provided:
# in your rails view
<%= text_field_tag(:station_text_field, ..., id: 'station-text-field') %>
// in your javascript
function request_stations() {
alert("calling request_stations");
};
const stationTextField = document.querySelector("#station-text-field");
stationTextField.addEventListener('keyup', (event) => {
request_stations();
});
Agree with mhunter's answer.
This post helped me get a grounding on this difference in Rails 6: https://blog.capsens.eu/how-to-write-javascript-in-rails-6-webpacker-yarn-and-sprockets-cdf990387463
What I don't see in your question is whether or not you did this in app/javascript/packs/application.js:
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("station")
The big difference in Rails 6 is that you have to deliberately:
require a JS file
deliberately export something from that file
deliberately import that something, in the file where you want to use it.
So if there is a function in station.js that you want to use, connect the steps above. Start with a simple function in station.js that fires upon DOMContentLoaded, and add a console.log("hey, station.js is alive and well"). If you don't see it, then something in those 3 steps is not right.
In pre-Rails6, you had a "garden" of JavaScript, just by virtue of being in the asset pipeline. In Rails 6, you have to be more deliberate.

How to use rails webpack loaded js in js erb template

I am using webpacker gem in rails 5.0 app, but I can't get the javascript to execute/be available in the js.erb I'm hitting on validation error. I'm sure that I'm violating some simple premise here, but can't find the answer and no compile or console errors are present. I do have the <%= javascript_pack_tag 'application' %> in my application.html.erb
Here is the setup:
app/javascript/packs/application.js:
import * as CustomerSession from 'customer_sessions';
console.log('Hello World from Webpacker');
app/javascript/customer_sessions/index.js:
export { univgwTabs } from './univgwTabs';
app/javascript/customer_sessions/univgwTabs:
export let univgwTabs = () => {
console.log('hi');
};
js erb template called on validation error of form:
$("#right_side_right_bottom_target").html("<%= j render partial: 'generic_object_new' %>");
CustomerSession.univgwTabs();
Global.resizeWindow();
If there is no issue with console.log(CustomerSession) in the location where you are importing it then the simplest fix I found was to just assign the imported variable as one of the global windows properties.
// in packs/application.js (or wherever your pack is)
// import
import * as CustomerSession from 'customer_sessions';
// assign
window.CustomerSession = CustomerSession
Assuming that there is no issues with webpacker, you should now be able to console.log(CustomerSession) in the console or your js.erb file.

Link rel='import' breaks Router

I'm experimenting with dart-polymer apps and have run into a few issues.
Is there a way to inject template declaration of a custom element through code? The docs currently specify the following method:
<link rel="import" href="my_element.html">
I'm trying to use the Route package (specifically 'package:route/client.dart'), and importing an html module via this method seems to break the router, so:
main() {
var router = new Router()
..addHandler(homeUrl, showHome)
..addHandler(signinUrl, showSignin)
..listen();
}
fails to execute the handlers when I navigate to the Url specified. If I remove the html import, the Router works fine.
Any way around this?

Dynamically add a WebComponent in Dart?

I was attempting to follow the code found here:
component_created_in_code_test.html
component_created_in_code.dart
However, when I get the dependencies and run the code in dartium, I get the following error. This error occurs when calling the create() method of ComponentItem (in the .dart code):
Breaking on exception: Class 'SayHello' has no instance method 'created_autogenerated'.
I rewrote them ever so slightly below (code is identical except main has been moved to be dart code rather than inlined):
<!-- component_created_in_code_test.html -->
<!doctype html>
<!--
Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
for details. All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<script src="packages/web_ui/testing/testing.js"></script>
</head>
<body>
<element name="say-hello">
<template>Hello {{name}}!</template>
<script type='application/dart' src="component_created_in_code.dart">
</script>
</element>
<say-hello name="component create in html"></say-hello>
</body>
</html>
and the following dart code,
//component_created_in_code.dart
library component_created_in_code;
import 'dart:async';
import 'dart:html';
import 'package:web_ui/web_ui.dart';
class SayHello extends WebComponent {
String name;
}
void main() {
Timer.run(() {
var hello = new SayHello()
..host = new DivElement()
..name = 'component created in code';
// "hello" is the DOM node.
// "hello.xtag" is your SayHello object.
// We are working on making these be the same object.
// If the component uses data-binding, we need to make sure the
// "lifecycle" methods get called. We are working to make this be
// automatic too.
var lifecycleCaller = new ComponentItem(hello)..create();
document.body.nodes.add(hello.host);
lifecycleCaller.insert();
window.postMessage('done', '*');
});
}
It would appear that this dart-lang example has a problem. Am I missing something or is the code just borked?
After getting this question answered, I packaged up the working solution to the problem.
component_created_in_code
Simply pull from git, and then import into dartEditor. Then 'pub install' and 'reanalyze source' (never hurts) from the editor, then right click "Run in Dartium" on "web/component_created_in_code.html".
It sounds like you need to run the Web UI compiler first. Either run packages/web_ui/dwc.dart on your HTML file, or write a build.dart along these lines:
import 'dart:io';
import 'package:web_ui/component_build.dart';
void main() {
build(new Options().arguments, ['web/component_created_in_code_test.html']);
}
I tested the same with build 0.5.13_r23552 editor & SDK and run into the same problem when running in Dartium. If I do the dart2js (Run as Javascript/Generate javascript) however, it works.
However, be aware of the following (based on my experience):
Try to change to the SDK version that it has been tested and verified with.
It seems the tests are updated to run with 0.5.15; while the SDK delivered with the editor on the dartlang site is only 0.5.13. Maybe clone the bleeding edge version to make it work?
Dart is constantly evolved. Always do pub update on your project after updating to the newest editor, if you are using dependencies and not a specific library version.
Add the build.dart to your project to make sure that code is generated on changes (See bottom of this page: Build.dart setup)

How to use Ruby on Rails 3.2 with 'yui 3.5'?

I'm writing write my first RoR application with YUI framework. I tried googling for ror+yui manuals with no success. So I went to YUI site. YUI says:
// Put the YUI seed file on your page.
<script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script>
Where it's supposed to be putted in RoR app?
I've tried to app/assert/javascripts/yui-min.js.
As a result i got <html class="yui3-js-enabled"> in every page. Supposing YUI is working now i've tried to copy-paste "Work with the DOM" example from YUI's page to app/public/index.html.
The error I received was:
Uncaught ReferenceError: YUI is not defined.
I tried the info in this link and it was not helpful to me:
https://stackoverflow.com/questions/1452829/tutorial-suggestions-on-yui-with-ruby-on-rails
Your first step in any rails app is to delete app/public/index.html ... then work in your pages inside of rails.
So that means create an app/views/layouts/application.html, and that's where you add your
<html>
<head>
<script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script>
Based on the link, you might not have it in your <head> and it needs to be.
UPDATE: (sample javascript code to change h1)
<script>
YUI().use('node', function (Y) {
var headerElement = Y.one('h1');
headerElement.setHTML("I have been updated");
});
</script>

Resources