What is the best practise for creating a view page in Rails with different view-options, such as a basic view with mostly text and an advanced view with graphical features? More specifically, I would like to have a view page where the the user can toggle between a basic/advanced show view. Clicking the toggle button renders one set of divs corresponding to selected view. Should this be done though a form_for/if-else statement in html markup or is it better do to do it in javascript? I guess turning the <div id="id"> on/off could be done in javascript through:
$("#id").show()
$("#id").hide()
I have a problem understanding how a rails implementation is done, where do I put the if-else statement (i.e. if user basic view is toggled render <div id="basic">, else <div id="advanced">)?
<%= form_for ??? do |f| %>
...
<%= f.submit ??? %>
<% end %>
Edit 2:
<div class="row">
<div class="span6">
<div class="btn-group" id="basic-advanced" data-toggle="buttons-radio">
<a class="btn btn-small" href="#" id="basicbutton">Basic</a>
<a class="btn btn-small" href="#" id="advancedbutton">Advanced</a>
</div>
</div>
</div>
<div class="container" id="basic">
This is the basic view
</div>
<div class="container" id="advanced">
This is the advanced view
</div>
Now in javascript I have the following:
$("#basic").toggle();
$("#basic-advanced").click(function (){
$("#basic").toggle();
$("#advanced").toggle();
});
I have added the above code, but how do I keep track of which viewing mode that the page is in? From the answers it seems like one could set an instance variable, #viewing_mode, to a value corresponding to the mode, but how should this be done? Through a form?
Update: I managed to achieve a toggle using a session variable, and an if/else statement, the procedure is described here: Session variable not persisting after switch.
If you are using jQuery.show() and jQuery.hide() that means you need both the basic and advanced div tags rendered. Rails needs to render them both. You can just have toggle display:hidden css, here I did that with variable #use_advanced.
<div id="advanced" <%= (#use_advanced) ? '' : ' style="display:hidden"' %>>...
<div id="basic" <%= (#use_advanced) ? ' style="display:hidden"' : '' %>>...
To toggle between the two you could have a button: <button>toggle</button>
$('button').click(function () {
$('#advanced').toggle();
$('#basic').toggle();
});
There are some different cases:
1) if you are able to change your view using CSS only - then you should enclose all the page inside classified div:
<div class='my-style'>
...
</div>
2) if first solution is not applicable then you may use if-else statement:
<% if #my_style_selected %>
<div>My style</div>
<% else %>
<div>Default</div>
<% end %>
3) finally, if neither solution suits you. You may write some JS to dynamically replace your divs. The best solution is to replace some parts of the page using AJAX. If you will render both variants and hide one of them - that will almost double your page load time.
Given that yiou are using rails I would look into using layout for different views rather than having conditional logic.
For more info see rails 3, how add a view that does not use same layout as rest of app?
Here's a JavaScript object (written in CoffeScript) that will allow you to switch between as many modes as you like using a convention:
class ModeSwitcher
constructor: ($area, modes) ->
$area = $ $area
me = this
bindToggle = (mode) ->
$area.find('a.toggle.' + mode).click ->
me.toggle mode
$ ->
bindToggle(mode) for mode in modes
toggle: (mode) ->
$('.mode').hide()
$('.' + mode + '.mode').show()
Here's an example of how you could construct the object (JavaScript/jQuery):
var switcher = new ModeSwitcher('body', ['basic', 'advanced']);
$(function() {
switcher.switch("<%= #mode %>");
});
The #mode instance variable is set in the Rails controller and says which mode the view should start out in:
#mode = params[:mode] || 'basic'
As for how it works by convention, you would have sections like this:
<div class="basic mode">...</div>
<div class="advanced mode">...</div>
And you would have links like this:
<a class="toggle advanced">Switch to advanced mode</a>
<a class="toggle basic">Switch to basic mode</a>
When constructed, the object will iterate through all the declared modes and look for the toggle links. It will then bind the toggling function to those links.
Related
Can HTML from an ejs template be injected via JQuery?
I have an Index file that has a navbar and a content area, as well as a sample TestButton template that I am trying to render.
Index.ejs
<ul>
.
.
<li id="listItem">Nav Bar Item</li>
</ul>
<div id="display">
</div>
<script>
$('#listItem').click( function(){
// Note - testButtonTemplate is being properly passed in from my routes
$('#display').html( <%- render( testButtonTemplate, {} ) %> );
});
</script>
TestButton.ejs:
<a href="#" class="btn btn-primary" id="test-button">
Click Me!
</a>
I did my best to simplify my code, but basically, when I click on a link from the nav bar, I want to dynamically load a page in the display div.
The nav bar works.
The click functionality works.
If I manuallay display the ejs template in the div, it works.
EX:
<div id="display">
<%- render( testButtonTemplate, {} ) %>
</div>
Otherwise, when I try to load the page with the sample code above, this is the error I get:
"Uncaught SyntaxError: Unexpected token <" and the raw html looks like:
.
.
<script>
$('#listItem').click( function(){
$('#my-test').html( <a href="#" class="btn btn-primary" id="test-button">
Click Me!
</a>
);
});
</script>
So you can see that the html has been properly retrieved from the ejs template class, but JQuery does not like how I am formatting that data. It looks like the data needs to be surrounded in quotes, but simply adding beginning and end quotes does not solve the problem.
I have tried seemingly every combination of quotes, escaped and unescaped html, storing the data in a variable first then trying to inject it, but none are working for me.
Is there an obvious mistake I'm making? I would prefer to solve the problem given my current tool set.
Try loading your template like this:
<script>
var template = new EJS({url: '/TestButton.ejs'});
$('#listItem').click( function(){
$('#display').html(template.render());
});
</script>
Hi I am trying to display text from another html document with AJAX in my rails app. I just wrote this small piece of code because I'm trying to learn AJAX. Can someone please explain to me what's going wrong with this piece of code?
Stepone.htm.erbl
<div class="margin-top">
<div class="container">
<h1> Do you like Math or Science </h1>
<br>
<div class="row">
<div class="col-4">
<button id="math1-1"> Math </button>
</div>
<br>
<div class="col-4">
<button> Science </button>
</div>
</div></div></div>
<br><br><br><br><br><br><br>
<script>
$(document).ready(function(){
$("#math1-1").click(function(){
$("#math1").load("math_1.html");
});
});
</script>
Math_1.html.erb
<div class="margin-top">
<div class="container">
<h1> Do you like Math or Science </h1>
<br>
<div id="math1">
Math_1
</div>
</div></div>
Because you're learning, let me give you some ideas:
Ajax
Ajax (Asynchronous Javascript And XML) is a type of functionality inside JQuery (it's pure XML Header Request / XHR in javascript). It basically sends a "pseudo-request" to an endpoint in your application, receiving & processing the response
The beauty of ajax is its asynchronous nature (working independently of any processes) - meaning you can use it to send a request "out of scope" of the typical application flow:
Typically used to create the appearance of providing the user with the ability to "interact" with the webpage (without it reloading), ajax has become prolific, not least due to JQuery's assimilation of the $.ajax() functionality into a single call
In simple terms - Ajax provides you with the ability to load & process a request on your front-end. This means if you want to use it, you need to be able to firstly have a way to process the result, and then ensure you're able to manage the response (typically by amending your DOM)
--
Structure
Since this is posted in the Rails section, let me give you some ideas on how to correctly get Ajax working with Rails. You need several important elements:
An endpoint
A backend controller action
A way to handle the response
You first need an endpoint. Simply, this is a route which will direct your ajax request to a specific controller action. The route itself is not important (Ajax is literally just a way to send "pseudo" requests to your system). What is important is the action the route will lead you to:
#config/routes.rb
resources :your_controller do
collection do
get :birthdays
end
end
#app/controllers/your_controller.rb
Class YourController < ApplicationController
respond_to :js, :json, :html, only: :birthdays
def birthdays
#birthdays = Model.where(birthday: Date.today)
respond_with #birthdays
end
end
This means that if you want to send an ajax request to the controller, you'll be able to do the following:
#app/assets/javascripts/application.js
$.ajax({
url: "/your_controller/birthdays",
success: function(data) {
$("#your_element").html(data);
}
});
--
Fix
As mentioned by EasyCo, the answer for you is to make sure you have an element to append your new data to. This is relatively simple, but I also want to discuss the importance of keeping your javascript unobtrusive with you
You should always put your javascript into the asset pipeline of Rails (IE /app/assets/javascripts/xxx.js). There are many reasons for this (DRY, Convention over Configuration), but the most important thing is to keep your application modular
Modularity is what gives great applications a natural "flow" and structure, allowing you to use / reuse as many functions as you require throughout the app. It is for this reason why I highly recommend you include any javascript in the respective JS files - as these then act as dependencies for your browser-based pages
So in essence, you'll want the following:
#app/assets/javascripts/application.js
$("#math1-1").on("click", function(){
$("#math1").get("/maths/1");
});
#app/views/maths/index.html.erb
<%= link_to "1", math_path("1") %>
<div id="math_1"> </div>
You need a DOM element with id="math1" in your Stepone.html.erb file.
You're trying to load math_1.html but it can't find an element with ID of math1 in Stepone.html.erm. It therefore doesn't load math_1.html because it has nowhere to append the data.
Change Stepone.html.erb to:
<div class="margin-top">
<div class="container">
<h1> Do you like Math or Science </h1>
<br>
<div class="row">
<div class="col-4">
<button id="math1-1"> Math </button>
</div>
<br>
<div class="col-4">
<button> Science </button>
</div>
</div></div></div>
<br><br><br><br><br><br><br>
<div id="math1"></div> <!-- AJAX will get loaded in this div -->
<script>
$(document).ready(function(){
$("#math1-1").click(function(){
$("#math1").load("math_1.html");
});
});
</script>
I have a directory page where the listings are rendered on the index page.
<% #listings.each do |listing| %>
# do some stuff
<% end %>
I've added a data-toggle to each listing - basically a button.
<a id="chat-menu-toggle" href="#dr" class="chat-menu-toggle" >
<div class="iconset top-chat-dark ">
<span class="badge badge-important hide" id="chat-message-count">1
</span>
</div>
</a>
This data-toggle opens a STATIC div. The div is a slider with content.
<div id="dr" class="chat-window-wrapper">
I want to use each button to pass the listing.id to a variable. Then, I can use that ID throughout the div.
For example:
Listing with ID:
Stack - 1
Overflow -2
Ruby - 3
Rails - 4
Onclick - 5
Let's say I click the button for "Ruby" which has an id of 3, I want the id to be passed around like so.
variable = 3
<div id= <%= variable %> class="chat-window-wrapper">
Not to sure what you mean by "use that ID throughout the div." but you could try this if it helps you?
<div data-id="<%=listing.id %>" class="chat-window-wrapper">
If you want to get the id's value from what ruby printed then you can try adding an event listener
$(".chat-window-wrapper").on("click",function() {
var x = parseInt($(this).attr('data-id');
}
To access listings outside iterator try
listings[index]
or
#allListings = listings. Then access #allListings[index]
but as far as my rusty ruby knowledge goes, i think listings should be accessible as long as the controller is passing it in the context to the view.
I have a div and need to render different .js.erb actions based on the clickevent on that div.
For example:
on dblClick, I want to render the new.js.erb
on click, I want to render show.js.erb
In my asset/javascripts directory I have a file.js.coffee:
$('#myDiv').on "dblclick" ->
$.getScript('/projects/xy/plan/new')
This basically works. It shows the modal in my new.js.erb:
$("#myModal").modal("show");
How can I make the $.getScript URL dynamic and include an object for the show and edit action?
Edit:
Rich Pecks answer seems to be correct.
Because of simplicity I just wrote $('#myDiv').on "dblclick".
The full example is:
$zoomcontainer = $("section").find(".parent")
$panzoom = $zoomcontainer.find(".panzoom").panzoom(
$zoomIn: $zoomcontainer.find(".zoom-in")
$zoomOut: $zoomcontainer.find(".zoom-out")
$zoomRange: $zoomcontainer.find(".zoom-range")
$reset: $zoomcontainer.find(".reset")
).on("dblclick", (e) ->
How should I put my data attributes in the HTML?
This is my basic HTML structure:
<section>
<div class="parent" data-project_id="<%= #project.id %>" data-plan_id="<%= #plan.id %>">
<input type="range" class="zoom-range" />
<div id="plan" class="panzoom" style="background: url('<%= #plan.asset.url %>') no-repeat;>
</div>
</div>
</section>
From what I can see, you could use a different event handler:
var plan_url = "/projects/xy/plan";
$('#myDiv').on "dblclick" ->
$.getScript(plan_url + '/new')
$('#myDiv').on "click" ->
$.getScript(plan_url + '/show')
Although this seems too simple to be what you're asking for
Dynamic
If you're looking to handle dynamic routes, you'll need to be able to pass the various object variables through your HTML (JS can't read Rails variables)
You'd have to do something like this:
#app/views/posts/show.html.erb
<%= content_tag :div, class: "your_class", data: {project_id: #post.project_id, plan_id: #post.plan_id} do -%>
Your div
<% end -%>
#-> <div class="your_class" data-project_id="15" data-plan_id="6">Your Div</div>
This will allow you to do this:
#app/assets/javascripts/application.js
$('#myDiv').on "dblclick" ->
project = $(this).data("project_id")
plan = $(this).data("plan_id")
$.getScript('/projects/' + project + '/plan/' + plan)
I am currently trying to write functional tests for a charging form which gets loaded on to the page via AJAX(jQuery). It loads the form from the charge_form action which returns the consult_form.js.erb view.
This all works, but I am having trouble with my testing.
In the functional I can go to the action but I cannot use assert_select to find a an element and verify that the form is in fact there.
Error:
1) Failure:
test_should_create_new_consult(ConsultsControllerTest) [/test/functional/consults_controller_test.rb:8]:
Expected at least 1 element matching "h4", found 0.
<false> is not true.
This is the view.
consult_form.js.erb:
<div id="charging_form">
<h4>Charging form</h4>
<div class="left" id="charge_selection">
<%= select_tag("select_category", options_from_collection_for_select(#categories, :id, :name)) %><br/>
...
consults_controller_test.rb:
require 'test_helper'
class ConsultsControllerTest < ActionController::TestCase
def test_should_create_new_consult
get_with_user :charge_form, :animal_id => animals(:one), :id => consults(:one), :format => 'js'
assert_response :success
assert_select 'h4', "Charging form" #can't find h4
end
end
Is there a problem with using assert_select with types other than html?
Thank you for any help!
So, the problem was that I should put javascript in .js and HTML in .html :P Kinda obvious.
I was putting html into a javascript file. I fixed it by simply renaming charge_form.js.erb to charge_form.html.erb.