javascript in rails not recognized - ruby-on-rails

This is a fairly simple question but I can't seem to figure out why it's not working
I have this code:
$(".positive").numeric({ negative: false }, function() { alert("No negative values"); this.value = ""; this.focus(); })
which works when I put it in my view between <script> and </script>
However, when I copy and paste that formula to app->assets->javascripts-> page.js.coffee it doesn't work. I have even tried copy and pasting that code to JS2Coffee converter and pasting the coffee version of the code. Still no luck.
What am I doing wrong that my view does not recognize the javascript in my assets?
Here is the code in coffescript:
$(".positive").numeric
negative: false
, ->
alert "No negative values"
#value = ""
#focus()
my application.js has
//= require jquery
//= require jquery_ujs
//= require jquery.numeric
//= require_tree .

Your CoffeeScript generates the following JavaScript:
$(".positive").numeric({
negative: false
}, function() {}, alert("No negative values"), this.value = "", this.focus());
As you can see, it's not the same.
Please note some things:
You do not have to use CoffeeScript. You can use plain JavaScript if you want to.
If you want to use CoffeeScript, please read up on its syntax. Most importantly: in CoffeeScript, whitespace is significant.
Your codesnippet could look like this, in correct CoffeeScript:
$(".positive").numeric
negative: false
->
alert "No negative values"
#value = ""
#focus()
The reason that your code isn't executed when you put it through the asset pipeline, is that it will end up in the head of the document, instead of the body, and hence it will be executed before the browser has finished loading the DOM.
In other words - there isn't any element to fetch yet.
To solve this, wrap you code with JQuery:
$ ->
# Your code goes here
JQuery will make sure that your code is executed only once the DOM is ready for manipulation.

Related

RAILS 6 - how to use EasyAutocomplete

I try the last hours to integrate EasyAutocomplete into RAILS 6. But not so easy.
What I did :
Install Javascript Package with yarn:
# yarn add easy-autocomplete
Add this in the file app/javascript/packs/application.js
import “easy-autocomplete”
Add this in the file app/assets/stylesheets/application.css
*= require easy-autocomplete
*= require easy-autocomplete.themes
Then start the Rails Server and refresh the Web Page.
Then try to use it. Go into the developer console and type :
var options = {
data: ["otto", "hans", "paula"]
};
$("#task_name_search_field").easyAutocomplete(options);
task_name_search_field was previously defined as id :
<input type="search" class="form-control" id="task_name_search_field">
I got this message:
TypeError: $(...).EasyAutocomplete is not a function
Any idea ?
I had the same problem. Turbolinks does not give access to the script, the code needs to be run after it is loaded, something like this:
document.addEventListener("turbolinks:load", function() {
var options = {
data: ["otto", "hans", "paula"]
};
$("#task_name_search_field").easyAutocomplete(options);
});
In order for the autocomplete to work, you need to add a script file to the application.js like this:
require("packs/youfile")
If it helps you, here is an example of my code:
document.addEventListener("turbolinks:load", function() {
$input = $("[data-behavior='autocomplete']")
var options = {
getValue: "full_name",
url: function(phrase) {
return "/search.json?q=" + phrase;
},
categories: [
{
listLocation: "cameras",
header: "<strong>Cameras</strong>",
}
],
list: {
onChooseEvent: function() {
var url = $input.getSelectedItemData().url
$input.val("")
Turbolinks.visit(url)
}
}
}
$input.easyAutocomplete(options)});
I suppose you wouldn't have included jquery in your application.js. You need to do explicitly as it doesn't get included automatically with rails 6 app.
I ran into a similar issue. I'm a n00b at Webpacker, but by default it doesn't seem to compile in the same order in which plugins are included.
To get around the issue I did this workaround which just wraps the plugin code in an anonymous jQuery function, like so:
(function($) {
//Eac plugin code
})(jQuery);
https://github.com/pawelczak/EasyAutocomplete/issues/200#issuecomment-212277620
Maybe there is a way in the configs to force compilation in the correct order. This looks promising https://stackoverflow.com/a/43005332/148390
Add script-loader to package.json then add
import 'script-loader!jquery/dist/jquery.min'
in app/javascripts/application.js
Check in your browser that $().jquery yields a proper result.

specific issue getting component- chip's jQuery to function properly in rails app

I have been beating my head against this for a day and a half now. I think I'm close though! I have two issues that I've searched high and low for. Broadly, I am trying to use Materialize within rails to use their "chips" component. It's seemingly most advanced option uses jQuery to auto-complete a search... once enter is hit it becomes a "chip." http://materializecss.com/chips.html
I finally got jQuery working by creating a users.js file which is supposed to allow me to just toss in jQuery calls to be reflected in my html view. Once I got this working, I tried to delete the portions of the code I didn't need to better identify what's doing what... I did this in codepen. https://codepen.io/robmatthews/pen/XgyERE
HTML
<div class="testing">
<div class="chips chips-initial"></div>
<div class="chips chips-placeholder"></div>
<div class="chips chips-autocomplete"></div>
</div>
jQuery
$(document).ready(function(){
$('.chips-initial').material_chip({
data: [{
tag: 'Apple',
}, {
tag: 'Microsoft',
}, {
tag: 'Google',
}],
});
$('.chips-placeholder').material_chip({
placeholder: 'Enter a tag',
secondaryPlaceholder: '+Tag',
});
$('.chips-autocomplete').material_chip({
autocompleteOptions: {
data: {
'Apple': null,
'Microsoft': null,
'Google': null
},
limit: Infinity,
minLength: 1
}
});
});
Once I got this working (note its the code from the materialize docs plus the document initialization that I assume you need... maybe you don't? The only part that has only worked for me in within the doc's example though is, of course, the one I want to use. On the doc's site, the auto-complete jQuery works... it doesn't in codepen... I have no idea why. I assume I need to add dropdown somewhere because I see that in inspect?? No idea.
Can anyone see what I am doing wrong? Here's what my appplication.js file includes with the users folder being positioned here: assets/javascripts/users
//= require jquery
//= require turbolinks
//= require materialize-sprockets
//= require_tree ./users/
This is only part of my problem. My next part will surely be when I am trying to modify the data object to serve up dynamic auto-fill options based on all of the existing users names being searched for! but I'll hold off on that until I get there. Thanks in advance! can't wait to figure out what my issue is...

Error on calling react-modal in rails 4 app

I'm having trouble using react-modal in my rails 4 app with a react-rails front end. I have already followed the steps in this SO question How to call react-modal from rails-assets.org in react-rails component and in this GitHub issue https://github.com/reactjs/react-rails/issues/510 but none of them seem to work.
This is the rails-assets gem in my Gemfile
source 'https://rails-assets.org' do
gem 'rails-assets-react-modal'
end
This is my application.js file
//= require react
//= require ./vendor/react-modal-v1.6.4
//= require react_ujs
//= require react-modal
The //= require ./vendor/react-modal-v1.6.4 call is a call to the compiled file for react-modal. I did this in accordance to the instructions provided in the github issue link above.
Finally, this is my component definition
var ModalTest = React.createClass({
getInitialState: function() {
return {
modalIsOpen: false
}
},
openModal: function() {
this.setState({modalIsOpen: true});
},
closeModal: function() {
this.setState({modalIsOpen: false});
},
render: function() {
return (
<div>
<button className="btn btn-primary" onClick={this.openModal}>
Open Modal
</button>
<ReactModal
isOpen={this.state.modalIsOpen}
onRequestClose={this.closeModal}
contentLabel="Modal"
>
<h1>Test Modal</h1>
</ReactModal>
</div>
);
}
});
I am getting the following error on the console:
Uncaught Error: react-modal: You must set an element with Modal.setAppElement(el) to make this accessible
What am I missing?
Thanks in advance, guys.
I found an answer from yachaka who posted in this GitHub issue for react-modal.
The script is loaded before the DOM, resulting in react-modal setting the parent element of the modal to document.body before it exists.
This can be fixed by adding the lifecycle method componentWillMount as follows:
componentWillMount: function() {
ReactModal.setAppElement('body');
}

How to resize images client side using jquery file upload

I am using blueimp jquery-file-upload in a Rails 3.2 app, via the jquery-fileupload-rails gem.
I am trying to resize images on the client side prior to uploading, but am having trouble following the documentation. My code is below. Currently uploading works perfectly, but the images are not resized.
What is the correct syntax to resize images via jquery-file-upload.
(Two approaches shown in the coffeescript based on this and this documentation. Neither works for me.)
#Coffeescript
jQuery ->
if $("#new_asset").length
$("#new_asset").fileupload
dataType: "script"
add: (e, data) ->
types = /(\.|\/)(jpe?g|png)$/i
file = data.files[0]
if types.test(file.type) || types.test(file.name)
data.context = $(tmpl("template-upload", file))
$('#progress-container').append(data.context)
jqXHR = data.submit()
$("button.cancel").click (e) ->
jqXHR.abort()
else
alert("#{file.name} is not a jpeg or png image file")
progress: (e, data) ->
if data.context
progress = parseInt(data.loaded / data.total * 100, 10)
data.context.find('.bar').css('width', progress + '%')
stop: (e, data) ->
$('.upload').hide()
process: [
action: "load"
fileTypes: /^image\/(gif|jp?g)$/
maxFileSize: 20000000 # 20MB
,
action: "resize"
imageMaxWidth: 1500
imageMaxHeight: 1500
,
action: "save"
]
dropZone: $(".dropzone")
sequentialUploads: true
disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator and navigator.userAgent)
imageMaxWidth: 1500
imageMaxHeight: 1500
downloadTemplateId: null
#application.js
//= require jquery-fileupload
EDIT
According to Matanza's answer, the add callback in my code prevents any processing functions from being called automatically. So I assume I need to do something like
...
add: (e, data) ->
$.each data.result, (index, file) ->
// processing code goes here
But I'm having a lot of trouble working out the correct syntax or making sense of the guides that are available.
How do I apply the resize processing to each file in the add callback?
I solved it by calling the process within the add callback like so:
add: (e, data) ->
current_data = $(this)
data.process(->
return current_data.fileupload('process', data);
).done(->
data.submit();
)
also remember to load your JS files in the right order in application.js....(this wasted several hours of my life):
//= require jquery-fileupload/vendor/jquery.ui.widget
//= require jquery-fileupload/vendor/load-image
//= require jquery-fileupload/vendor/canvas-to-blob
//= require jquery-fileupload/jquery.iframe-transport
//= require jquery-fileupload/jquery.fileupload
//= require jquery-fileupload/jquery.fileupload-ui
//= require jquery-fileupload/jquery.fileupload-process
//= require jquery-fileupload/jquery.fileupload-validate
//= require jquery-fileupload/jquery.fileupload-image
If that is still relevant-
I found out that once you use the add callback, it is your responsibility to add whatever processing stages that you require. So for that matter if you remove the add callback it will resize the image with your settings.
what you should do is register the resize processing settings to each file in the add function
hope that helps
I had trouble getting Image resize to work. In the end I started again. I had added image resize to an existing working file upload code. For me, it was the custom add that was hindering the resize. Once I removed the custom add, it was hunky-dorey. Just wanted to put it out there for the benefit of other strugglers.

Jquery calls not working in $viewContentLoaded of Angular

Unable to call jquery functions in $viewContentLoaded event of Angular controller, here is the code for the same.
$scope.$on('$viewContentLoaded', function() {
jQuery.growlUI('Growl Notification', 'Saved Succesfully');
jQuery('#category').tree()
});
Is any configuration required here?? I tried even noConflict(); var $jq = jQuery.noConflict();
Does it require any other configuration?
Thanks,
Abdul
First thing first, don't do DOM manipulation from controller. Instead do it from directives.
You can do same thing in directive link method. You can access the element on which directive is applied.
Make sure you load jquery before angularjs scripts, then grawlUI, three, angularJS and finally your application script. Below is directive sample
var app = angular.module("someModule", []);
app.directive("myDirective", function () {
return function (scope, element, attrs) {
$.growlUI('Growl Notification', 'Saved Succesfully');
element.tree();
};
});
angularjs has built in jQuery lite.
if you load full jquery after angular, since jQuery is already defined, the full jquery script will skip execution.
==Update after your comment==
I reviewed again your question after comment and realised that content which is loaded trough ajax is appended to some div in your angular view. Then you want to apply element.tree() jquery plugin to that content. Unfortunately example above will not work since it is fired on linking which happened before your content from ajax response is appended to element with directive I showed to you. But don't worry, there is a way :) tho it is quick and dirty but it is just for demo.
Let's say this is your controller
function ContentCtrl($scope, $http){
$scope.trees=[];
$scope.submitSomethingToServer=function(something){
$http.post("/article/1.html", something)
.success(function(response,status){
// don't forget to set correct order of jquery, angular javascript lib load
$.growlUI('Growl Notification', 'Saved Succesfully');
$scope.trees.push(response); // append response, I hope it is HTML
});
}
}
Now, directive which is in controller scope (it uses same scope as controller)
var app = angular.module("someModule", []);
app.directive("myDirective", function () {
return function (scope, element, attrs) {
scope.$watch("trees", function(){
var newParagraph=$("<p>" + scope.trees[scope.trees.length-1] + "</p>" ); // I hope this is ul>li>ul>li...or what ever you want to make as tree
element.append(newParagraph);
newParagraph.tree(); //it will apply tree plugin after content is appended to DOM in view
});
};
});
The second approach would be to $broadcast or $emit event from controller (depends where directive is, out or in scope of controller) after your ajax completes and you get content from server. Then directive should be subscribed to this event and handle it by receiving passed data (data=content as string) and do the rest as I showed you above.
The thing is, threat that content from ajax as data all the way it comes to directive, then inject it to element in which you want to render it and apply tree plugin to that content.

Resources