I am trying to use the bootstrap input spinner in my scalajs app. But when I try to use it I am getting the error "jQuery is not defined", even though I have included it in my project. Can someone tell me what I am missing?
So if I define a build.sbt:
name := "repro"
version := "1.0"
scalaVersion := "2.12.8"
scalaJSUseMainModuleInitializer := true
mainClass in Compile := Some("App")
enablePlugins(ScalaJSPlugin)
enablePlugins(ScalaJSBundlerPlugin)
webpackBundlingMode := BundlingMode.LibraryOnly()
libraryDependencies ++= Seq(
"org.querki" %%% "jquery-facade" % "1.2"
)
npmDependencies in Compile ++= Seq(
"bootstrap" -> "4.3.1",
"jquery" -> "3.2.1",
"bootstrap-input-spinner" -> "1.11.8",
)
And then try to use it in my app as follows:
#js.native
trait BootstrapInputSpinner extends JQuery {
def inputSpinner(options: js.Object = js.Dynamic.literal()): BootstrapInputSpinner = js.native
}
object BootstrapInputSpinner {
#JSImport("bootstrap-input-spinner", JSImport.Default)
#js.native
object Import extends BootstrapInputSpinner
val _import = Import // explicitly import it
implicit def bisExtensions(query: JQuery): BootstrapInputSpinner =
query.asInstanceOf[BootstrapInputSpinner]
}
object App {
import BootstrapInputSpinner._
def main(args: Array[String]): Unit = {
$(dom.document.getElementById("spinner")).inputSpinner()
}
}
My html file is defined as follows:
<!DOCTYPE html>
<html>
<head>
<title>Test User interface</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="app-container" id="root">
<input id="spinner" type="number"/>
</div>
<script src="repro-fastopt-library.js"></script>
<script src="repro-fastopt-loader.js"></script>
<script src="repro-fastopt.js"></script>
</body>
</html>
Note that if I don't refer to the bootstrap-input-spinner library and try to use jQuery on its own it works fine. For example there are no errors if I change my App object to:
object App {
// import BootstrapInputSpinner._
def main(args: Array[String]): Unit = {
println($(dom.document.getElementById("spinner")))
}
}
Also, I checked the -library.js file and it has the following code:
module.exports = {
"require": (function(x1) {
return {
"jquery": __webpack_require__(2),
"bootstrap-input-spinner": __webpack_require__(3)
}[x1]
})
}
Which tells me that jquery should be imported first?
I could guess from looking at the code, that you might need to add jQuery script too, before the library script that depend on.
Side note: You must check the compatibility of the bootstrap version and the jquery it depends
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
<script src="repro-fastopt-library.js"></script>
<script src="repro-fastopt-loader.js"></script>
<script src="repro-fastopt.js"></script>
Which of the scripts depend on jquery?
repro-fastopt-library or
repro-fastopt-loader or
repro-fastopt
It could be the import order when you bundle them.
I created a minimal website in Play that lets users upload a file. Although the code involved is rather simple, I can't find the reason for this compilation error:
Cannot write an instance of views.html.uploadFile.type to HTTP response. Try to define a Writeable[views.html.uploadFile.type]
Here are the contents of views.uploadFile.scala.html:
#helper.form(action = routes.FileUpload.handleUpload, 'enctype -> "multipart/form-data") {
File to upload: <input type="file" name="uploadedFile">
<div> <input type="submit"> </div>
}
That's the controller displaying the file upload form and handling the uploaded file:
package controllers
import play.api.i18n.{MessagesApi, I18nSupport}
import play.api.mvc._
import javax.inject.Inject
class FileUpload #Inject()(val messagesApi: MessagesApi) extends Controller with I18nSupport {
def uploadForm = Action {
Ok(views.html.uploadFile)
}
def handleUpload = Action(parse.multipartFormData) { request =>
import java.io.File
request.body.file("uploadedFile") match {
case Some(file) =>
val fileName = file.filename
val uploadDir = "/tmp/uploadedFiles/"
file.ref.moveTo(new File(uploadDir + fileName))
Ok(s"File uploaded: $fileName")
case None =>
Redirect(routes.FileUpload.uploadForm()).flashing(
"error" -> "File invalid")
}
}
}
And for the sake of completeness, here's my routes file:
GET /uploadForm #controllers.FileUpload.uploadForm
POST /upload #controllers.FileUpload.handleUpload
I overlooked the missing parentheses in the controller's action:
def uploadForm = Action {
// instead of Ok(view.html.uploadFile)
Ok(views.html.uploadFile())
}
Adding them makes the application compile fine.
Hello there Grammarians,
The documentation only shows:
flashing("success")
Do failures never happen if I use play? I've tried "failure" & "error" they don't do anything
You can either pass in a Flash instance or tuples of Strings. It doesn't have to be a specific String. Important is that you handle whatever you stick into the flash scope.
consider this example (Play 2.3.4):
Application.scala
package controllers
import play.api.mvc._
object Application extends Controller {
def index = Action { implicit req =>
Redirect(routes.Application.flash()).flashing("something" -> "show this text")
}
def flash = Action { implicit req =>
Ok(views.html.index("Flash!"))
}
}
index.scala.html
#(title: String)(implicit flash: Flash)
<!DOCTYPE html>
<html>
<head>
<title>#title</title>
</head>
<body>
<h1>#flash.get("something")</h1>
</body>
</html>
routes
# Home page
GET / controllers.Application.index
GET /flash controllers.Application.flash
I am looking at an example from Spring In Practice. I have the following controller:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/users")
public class AccountController {
private static final Logger LOG = LoggerFactory.getLogger(AccountController.class);
#RequestMapping(value = "/new", method = RequestMethod.GET)
public String getRegistrationForm(Model model) {
model.addAttribute("account", new AccountForm());
return "users/registrationForm";
}
#RequestMapping(value = "", method = RequestMethod.POST)
public String postRegistrationForm(AccountForm form) {
LOG.info("Created registration: {}", form);
return "redirect:/users/registration_ok.html";
}
}
The URL "/main/users/new" in this controller creates a new AccountForm object and returns it to the view /main/users/registrationForm. Here is that jsp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1 /DTD/xhtml1-strict.dtd">
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>New user registration</title>
</head>
<body>
<h1>New user registration</h1>
<form:form cssClass="main" action="." modelAttribute="account">
<p>All fields are required.</p>
.... Form fields here ....
</form:form>
</body>
</html>
The book indicates to use action="." to post the form submission to /main/users. I am wondering if the reason action="." posts to /main/users is because this form was 'called' by a method in a controller mapped to /main/users and the "." specifies to post to this URL? The book does not explain this. Thank you in advance.
. is a relative URI like any other; it points to the current “directory”. In /main/users/new, that’s /main/users/. .. would be /main/.
Consider the case when the action is create instead; you’d end up with /main/users/create. . makes it /main/users/. According to section 5.2.4 of RFC 3986, that becomes /main/users/. (You can find a full description of every step in resolving a relative URI there, too.)
I want to do something that I think will be a good way to use "Coffee Script Class" and Angular JS structures.
<!doctype html>
<html ng-app>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width, initial-scale=1">
<title>Main Test</title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/angular.min.js"></script>
<script type="text/javascript" src="js/coffee.js"></script>
</head>
<body>
<div ng-controller="MainClass" style="margin-left:10px">
<h2>All todos: {{test()}}</h2>
</div>
</body>
</html>
Notice than I setup the DIV ng-controller as MainClass and binding test() method inside a H2 HTML tag.
class AngularJSController
constructor: ($scope, $main) ->
$scope.test = MainClass.prototype.test
MainClass.test = MainClass.prototype.test
$main.test = MainClass.prototype.test
test = MainClass.prototype.test
#test = MainClass.prototype.test
console.log #test
class MainClass extends AngularJSController
constructor: ($scope) ->
super $scope, this
setTimeout (->
console.log test()
), 1000
test();
test: -> 'aloha!'
In AngularJSController constructor I've tried all forms I imagined to setup my super class method TEST on MainClass scope without success.
I'm trying to do it because I want to work with classes just on my Angular JS controllers and components.
Problems I already fell:
If I try to use #test() instead of test() inside setTimeout, jQuery already replaced the this property with a kind of JQuery Window Object.
setTimeout (-> console.log #test()), 1000
I don't know what really the scope of test() calls, if a place this (or # cause Coffee), isn't the same of place anything.
test() != this.test() != #.test() # the first scope isn't the same scope of last two calls
I have used the following syntax:
app = angular.module 'myapp', []
class MySimpleCtrl
#$inject: ['$scope']
constructor: (#scope) ->
#scope.demo = 'demo value'
#scope.clearText = #clearText
clearText: =>
#scope.demo = ""
app.controller 'MySimpleCtrl', MySimpleCtrl
angular.bootstrap document, ['myapp']
Take a look at this jsFiddle:
http://jsfiddle.net/jwcMA/
Here's a generic approach with a base class:
http://www.devign.me/angular-dot-js-coffeescript-controller-base-class/
BaseCtrl.coffee
# dependency - Function.prototype.bind or underscore/lodash
app = angular.module 'someApp'
class #BaseCtrl
#register: (app, name) ->
name ?= #name || #toString().match(/function\s*(.*?)\(/)?[1]
app.controller name, #
#inject: (args...) ->
#$inject = args
constructor: (args...) ->
for key, index in #constructor.$inject
#[key] = args[index]
for key, fn of #constructor.prototype
continue unless typeof fn is 'function'
continue if key in ['constructor', 'initialize'] or key[0] is '_'
#$scope[key] = fn.bind?(#) || _.bind(fn, #)
#initialize?()
BookFormCtrl.coffee
app = angular.module 'someApp'
class BookFormCtrl extends BaseCtrl
#register app
# list of dependencies to be injected
# each will be glued to the instance of the controller as a property
# e.g. #$scope, #Book
#inject '$scope', 'Book'
# initialize the controller
initialize: ->
#$scope.book =
title: "Hello"
# automatically glued to the scope, with the controller instance as the context/this
# so usable as <form ng-submit="submit()">
# methods that start with an underscore are considered as private and won't be glued
submit: ->
#Book.post(#$scope.book).then =>
#$scope.book.title = ""
setTimeout isn't related in any way to jQuery, but function passed to setTimeout is indeed executed in the global(window) context. Use fat arrow to explicitly bind it to the current scope.
http://coffeescript.org/#fat_arrow
setTimeout (=>
console.log #test()
), 1000
Sorry, I'm not sure what are you asking about.
Angular does supports Coffescript classes!, for the most part.
I've found issues with using RequireJs, expecting a function instead of an object.
take a look here :
http://softwareninjaneer.com/blog/writing-angularjs-controllers-coffeescript-classes/
I didn't have luck with #malix's answer although it did lead me to a solution that works. Here's how I'm doing mine:
'use strict'
class ImportsCtrl
constructor: ($scope, Import) ->
Import.query().then (imports) -> $scope.imports = imports
angular.module("greatDealsApp").controller "ImportsCtrl", ImportsCtrl
And here's a contrived example of turning $scope into a property of ImportsCtrl:
'use strict'
class ImportsCtrl
constructor: ($scope, Import) ->
#scope = $scope
#Import = Import
#loadImports()
loadImports: =>
#Import.query().then (imports) => #scope.imports = imports
angular.module("greatDealsApp").controller "ImportsCtrl", ImportsCtrl
And I don't know for sure if this matters, but I'm using ng-annotate.
It's impossible. You can't set a controller as an object (MainClass), because AngularJS ensures that the controller is a function.
You need to customize AngularJS to do it. I think it's not a good idea.
References
https://github.com/angular/angular.js/blob/master/src/ng/controller.js
https://github.com/angular/angular.js/blob/master/src/Angular.js