Assets in JavaScript - Symfony2 - javascript

I've got a problem, I am using Head.js plugin to import several js files in my template. Each file has a normal path e.g. assets/js/clock/date.js
The problem is that neither I can use the path directly in importing nor using the twig asset() function to get path to these files. As an example this is what I have in a separate js file
head.js("../assets/js/newsticker/jquery.newsTicker.js", function() { ... });
How can I get access to the files in folder assets inside a javascript file?

What you need is a global javascript defined variable in your twig which contains the path of whatever you want to load; for example
var generalPath = "{{ asset('path/to/your/asset') }}";
now you can call the function as header.js by concatenating with the defined global variable as
head.js(generalPath + 'jquery.cookie.js');

Related

Rails 6 - what is the proper way to load custom JS files?

I struggle to properly configure and set up my own JS files that contain JS functions for specific tasks.
I went through some articles and found that I need to place my custom JS to the JS packs folder -> app/javascript/packs/currency_calculations.js:
currency_calculations.js:
function convert_curr(from, to) {
...
}
function show_convertion(curr) {
...
}
...
and then I try to add this custom JS file to app/javascript/packs/application.js:
import Rails from "#rails/ujs";
import "#hotwired/turbo-rails";
import * as ActiveStorage from "#rails/activestorage";
import "channels";
import "controllers";
Rails.start();
ActiveStorage.start();
import "stylesheets/application";
// my custom JS file
import "packs/currency_calculations" // I also tried import "currency_calculations" -- same result
I also tried to add the following to the application.html.erb file:
= javascript_pack_tag 'currency_calculations'
It didn't work either.
I am still getting this error:
Uncaught Error: Cannot find module 'currency_calculations'
and when trying to call a function from a view, then:
Uncaught ReferenceError: convert_curr is not defined
What is the correct way to wire this up? I am used from Rails 5 to put all my JS functions to a js file and this file just to add to a app/assets/javascripts/application.js like this:
//= require currency_calculations
and then, in a view, I am able to simply call the wanted JS function like convert_curr("a", "b").
Thank you in advance.
There's a couple of ways to do this in Rails 6.
The first would be to create a custom directory and require it in the application.js file. In this case you could create a directory like this:
app/javascript/custom/currency_calculations.js
Then you would need to require it in your application.js file as such:
// app/javascript/packs/application.js
// ...
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("custom/currency_calculations")
That same method could also be streamlined if you, say, named your custom folder "currency" and then named the .js file index.js.
You could then just call it like this:
require("currency")
Require will look for the index file by default in the folder. But in that scenario, an index file must be present, or it will fail.
The other way to do this, in the event you don't want that JS to be compiled with everything else, is to use the javascript_pack_tag.
In that case, add the js file to your app/javascript/packs directory. Then use the pack tag helper where you need it such as:
<%= javascript_pack_tag 'currency_converter' %>
The last thing I would mention... are you sure there's no other library needed to make it work (such as JQuery)? In that case you would need to install and import that library to your application.js before you called the js file you're trying to execute.
I think the problem is you are not exporting anything in your js file. Try doing this in currency_calculations.js
const funcs = {
convert_curr() { console.log('foo') },
show_convertion() { console.log('bar') },
}
export default funcs;
And then in your code you call them with funcs.convert_curr()
Also it seems that currency_calculation shouldn't be it's own pack (you can think of a pack kinda like what application.js was in sprockets), so better be just a standalone js file outside the packs dir. (could be javascript/currency_calculations.js or javascript/utils/currency_calculations.js)
Some comments that may help you:
1 ) when you put a js file at /packs, it's going to be compiled as a standalone asset you can reference using javascript_pack_tag, so you don't need to add it to the application.js pack
you have two options depending on what you want:
move the file to javascript/src/currency_calculations.js and import it in your application.js as import 'src/currency_calculations' or import '../src/currency_calculations'
use it as a pack, remove it from application.js and use load it like javascript_pack_tag 'currency_calculations'
(you can have the file loaded both in application.js and as a standalone pack, but you'll have the code twice)
2 ) if you want to access the functions from that file in your view, you can't do it just like sprocket does. sprockets adds the content of that file in the global scope while webpacker contains the functions in the bundle context. If you want the functions to be available globally from your views, you have to make them global doing something like
global.convert_curr = function(from, to) {
...
}
(you can also use window.convert_curr = ...)

How to include/import an entire JS file with Webpack

I am new to Webpack, but I have a habit of building my web apps in the following manner:
Declare a global variable for the project.
Create several JS files that use the global variable to declare functions and variables
Link these separate js files in the HTML file, and combine them when going to production.
For example my first JS file would be "init.js":
let FP = {}; // Global Object
My second would be "processing.js":
FP.addNumbers = function(a, b){
return a+b;
}
The HTML would include:
<script src="init.js"></script>
<script src="processing.js"></script>
Then in production I use a node plugin I wrote to parse the HTML page and combine all the JS files into one.
I want to do something similar with Webpack, but the only way I found to combine files is with "include". Which requires each file use a separate variable name.
I literally just want to dump the contents of my separate JS files into init.js. Is there a way to do this?
If you're going to use Webpack to bundle your code, the right approach to something like this would be to take advantage of modular imports and exports to coordinate data between modules, otherwise the use of Webpack isn't really doing anything for you.
For example, here, try the following:
// index.js
import { addFns } from './addFns.js';
const FP = {};
window.FP = FP; // use this if the object needs to be global
addFns(FP);
// addFns.js
export const addFns = (FP) => {
FP.addNumbers = function(a, b){
return a+b;
}
};
Then, Webpack can create the complete bundle with only a single .js file as output automatically, and it'll be ready for production with any more post-processing.

Reference relative path inside JS config file in MVC

I'm trying to incorporate this scanning software into an application.
The folder which contains all the necessary .js, .css and binary files is called Resources.
In my MVC app - I have placed the Resources file inside my Scripts folder.
In my .cshtml, I have the following:
#section scripts {
<script src="~/Scripts/Resources/dynamsoft.webtwain.config.js"></script>
<script src="~/Scripts/Resources/dynamsoft.webtwain.initiate.js"></script>
}
Which loads the scripts successfully.
The issue I'm facing is the scripts themselves reference relative paths within the Resources folder.
In dynamsoft.webtwain.config.js - you can set the path to the resources folder - I have mine set to the following:
Dynamsoft.WebTwainEnv.ResourcesPath = '~/Scripts/Resources';
However when the page loads - I'm receiving 404 errors for some of the files because it's trying to literally interpret the path:
I have also tried the following but with no luck:
Dynamsoft.WebTwainEnv.ResourcesPath = '#Url.Content("~/Scripts/Resources")';
As far as I know you can't use relative paths starting with tilde (~) in separate JS files because #Url.Content() helper and ASP.NET relative paths only work inside Razor view page, but you can pass the relative path by creating root path in JS global scope (i.e. Razor view page's <script> tag) like this:
<script>
var baseUrl = '#Url.Content("~")';
</script>
Then you can include the path inside JS files using that variable:
// custom JS file
if (typeof baseUrl !== 'undefined') {
Dynamsoft.WebTwainEnv.ResourcesPath = baseUrl + '/Scripts/Resources';
}
Or simply mentioning full path & pass it:
#* Razor page *#
<script>
var resourcesPath = '#Url.Content("~/Scripts/Resources")';
</script>
// custom JS file
if (typeof resourcesPath !== 'undefined') {
Dynamsoft.WebTwainEnv.ResourcesPath = resourcesPath;
}
Another alternative is using custom JS view engine together with file handler for JS scripts like example below:
// custom JS engine
public class CustomJSEngine : BuildManagerViewEngine
{
public CustomJSEngine()
{
ViewLocationFormats = new[]
{
"~/Scripts/{0}.js",
"~/Scripts/Resources/{0}.js"
};
FileExtensions = new[]
{
"js"
};
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var view = new RazorView(controllerContext, viewPath,
layoutPath: masterPath, runViewStartPages: true, viewStartFileExtensions: FileExtensions,
viewPageActivator: ViewPageActivator);
return view;
}
}
// put these lines below inside Application_Start()
RazorCodeLanguage.Languages.Add("js", new CSharpRazorCodeLanguage());
ViewEngines.Engines.Add(new CustomJSEngine());
// add this line if necessary
WebPageHttpHandler.RegisterExtension(".js");
References:
#Url.Content in separate javascript file using ASPNET MVC 3 and Razor
Returning razor-parsed Javascript as a ViewResult from a controller

Global variables are undefined for imported Javascript functions

Trying to figure out if there is a problem due to the import/export method, or if my architecture just bad....
Previously, I had multiple files of javascript. Just functions, no classes. In one "center/main" JS file, there are global variables. These variables are accessed and used/updated by functions in that same file, as well as other files. Each JS file had to have its own tag within the index.html
The move was then to switch to webpack as a module builder which would remove the need for all those script tags. Instead I just have to import/export the functions.
The problem is that now after using that method, the global variables are undefined to the imported functions Below is the setup dumbed down, but I don't see why it would be a problem. Maybe I'm missing something.
main JS file
import * as SettingsFile from './settings';
var myVariableUsed;
$(document).ready(function() {
myVariableUsed = "test";
SettingsFile.startSettings();
});
secondary JS file (settings.js)
export function startSettings(json) {
console.log(myVariableUsed);
}
Hy, i think you can understant what is happening with this article:
https://medium.com/webpack/brief-introduction-to-scope-hoisting-in-webpack-8435084c171f
To be short, webpack creates a new scope for required files, because of 'use strict' declaration on generated code output.
To pass parĂ¢meters to required modules you need to do do something like this:
// somefile
require("lib.js")(param1, param2)
// lib.js
module.exports = function(param1, param2) { }

Webpack function import not accessible by JS on page

First time learning webpack with Laravel 5.5.
I have a helpers.js library which I include into my app.js bunlde like this:
import * as $mh from './helpers.js';
An example function in helpers.js is:
export function valRemoveHighlight(element)
{
$(element).closest('.form-group, .input-group, .has-feedback').removeClass('has-error').addClass('has-success');
}
I can then access this function inside the bundle like this:
$mh.valRemoveHighlight(element);
But I have JS script at the bottom of my page which cannot access the function in the bundle. I have tried different scopes with no success:
window.$mh.valRemoveHighlight(element);
$mh.valRemoveHighlight(element);
valRemoveHighlight(element);
How do I make these exported / imported helper functions accessible in the global scope, so any inline / page script can access them?
Ideally kept within the helpers scope $mh. but accessible from the page / script like:
$mh.valRemoveHighlight(element);
Thanks!
$mh is only available inside of app.js, so you will have to expose that function yourself inside your app.js by doing : window.$mh = $mh

Categories