Ruby on Rails: Pulling HTML string of specific element from within controller - javascript

If I have a view that is rendered with the following element:
View
<div id="content">
<!-- More HTML -->
</div>
In my controller, is there such a method where I could retrieve the HTML string of a specific element using its id? For example, it might look something like:
def myview
contentString = get_html_element_string("content")
...
end
where contentString would contain the value <div id="content"> <!-- More HTML --> </div> as a string.
I understand you can fetch the HTML of the whole rendered page using render_to_string, but I'd rather not parse through that.

It's not really possible to access the rendered content after the fact in the controller.
I would recommend creating a helper function to create the content that goes inside the content div. Then call the helper in the myview if you need it there.
The following post gives some options for calling a helper within a controller:
Rails - How to use a Helper Inside a Controller

I actually ended up putting the HTML I need within a partial and rendering it from within the controller (and again later in my view using <%= render partial: "content_partial" %>).
_content_partial.html.erb
<div id="content">
<!-- More HTML -->
<%= #my_value.function %>
</div>
And within my controller:
def myview
contentString = render_to_string(:partial => 'content_partial', :layout => false, :locals => {:my_object => #my_value})
...
end

Related

Underscore template <script type="text/template></script> and nested quotes

I'm working on a Laravel/Blade project and I'm using underscore to render content on the page. As a very simple example, in my blade file I have:
<div class="test-template">
</div>
<script class="template-container" type="text/template">
<div class="sample-class">
<h1><%= title %></h1>
</div>
</script>
My javascript to render the template looks like this:
var template = _.template( $( ".template-container" ).html() );
var markup = template({
title: 'Title'
});
$('.test-template').html(markup);
The issue I'm having is that when the template is rendered every attribute that has quotes around it (in my blade file) gets wrapped in two sets of quotes.
Does anyone know how to prevent this double wrapping? I realized that if I remove the quotes from the class name in my blade file it technically renders the quotes properly. The problem there is that I can't use more than one class name per element.

Rails: Medium Editor not working with html stored in database

I use the Medium editor to be able to edit some content and then store it to the database. For the "new" view, I display the html from a template using render. Then for the "edit" view I display the html with a query to the database.
The Medium editor shows up for the "new" view but not for the "edit" view (but contenteditable is true). Any idea why it's not working for this specific view?
New view:
<nav id="nav_sections">
<ul id="ul_menu">
<li id="header_nav">GO TO SECTION</li>
<li>Introduction</li>
</ul>
<%= render 'form', guide: #guide %>
</nav>
<%= render 'layouts/template' %>
<% content_for :save_js do %>
<script type="text/javascript" src="/javascripts/lib/save.js"></script>
<script type="text/javascript" src="/javascripts/lib/menu.js"></script>
<% end %>
Edit view:
<nav id="nav_sections">
<ul id="ul_menu">
<li id="header_nav">GO TO SECTION</li>
<li>Introduction</li>
</ul>
<%= render 'form', guide: #guide %>
</nav>
<%= raw #guide.html %>
<% content_for :save_js do %>
<script type="text/javascript" src="/javascripts/lib/menu.js"></script>
<script type="text/javascript" src="/javascripts/lib/save.js"></script>
<% end %>
Save.js:
$('.container_content').children('section').children().each(function (element) {
if ($(this).is("section")) {
$(this).each(function () {
$(this).children().each(function () {
$(this).addClass( "changeable" );
});
});
}
else {
$(this).addClass( "changeable" );
}
});
var editor = new MediumEditor('.changeable');
var contents = $('.changeable').html();
var new_content = $('.container_content').clone().wrap('<p>').parent().html();
$('#input').val(new_content);
$('.changeable').blur(function() {
if (contents!=$(this).html()){
var guide = $('.container_content').clone().wrap('<p>').parent().html();
$('#input').val(guide);
contents = $(this).html();
}
});
Source code of the "new" view, the Medium Editor is loaded:
Source code of the "edit" view, the Medium Editor is not loaded:
I don't know rails very well, so I'm not sure what the difference between a "save view" and an "edit view" are. Are these completely separate pages that you navigate between via browser navigation or do you switch between these views without a separate page load?
It might help to see what some of the actual html looks like, particularly the html that contains the .container_content element, the <section> elements, and the #input element.
I'm not sure what is contained in menu.js, but one difference between the views is that menu.js and save.js are loaded in different orders, so there could be something there.
Some other MediumEditor tips that could help you:
editor.getContent(index) and editor.serialize() are two helper
methods for retrieving the html within the editor.
getContent(index) lets you get the html content of one element
within the editor, while serialize() will return JSON that contains
the innerHTML of all the elements within the editor.
Similar to editor.getContent(index), there's also a
editor.setContent(html, index) method which will allow you to
specify the html of an element within the editor. This is the preferable way to populate an editor element after the MediumEditor object has been instantiated.
If you're attempting to add more elements to the same instance of the editor after its already been instantiated, you should use the editor.addElements() helper method.
Documentation for the helper methods I've called out can be found here.

rails render view onclick with javascript

I'm trying to create a view, where users can click on different buttons and render different content based on the buttons they click. I've tried getting this done with JS but can't really get it to work. I made a button in my view:
<div class="link">
<%= link_to "Greetings", "#" %>
</div>
<div id="show"></div>
then in job.js.erb:
$(function() {
$('.link').click(function() {
$('#show').append("<%=escape_javascript render(:partial => 'show' %>");
});
});
unfortunately render is not supported in assets, but I don't really know what the best way is to make this happen.
One way you can try is to let the button click go to a controller action, by AJAX, and then render the file with name <action_name>.js.erb. this file will then be able to call the render action.
I will expatiate more with the following:
Assuming the resource in question is Greetings and you have a dynamic_show action in the Greetings controller, for example, and you have a dynamic_show_greetings_path routing to this action.
From inside your view, you can have:
<div class="link">
<%= link_to "Greetings", dynamic_show_greetings_path, remote: true %>
</div>
<div id="show"></div>
and the Greetings#dynamic_show action will be like follow:
def dynamic_show
respond_to do |format|
format.js
end
end
then, in your view directory, you have a dynamic_show.js.erb file, which will contain the script to append the dynamic view as follow:
$('#show').html("<%=escape_javascript render(:partial => 'show') %>");
And that solves it for you!
Of course, to now make it dynamic, you have to then pass in params to the controller, and then render content based on the response gotten.
PS:
setting remote: true on the link ensures that the call will be an AJAX call.
controller actions by default renders the file with same name as the action name, therefore, dynamic_show responding to js will render dynamic_show.js.erb
Hope this throws a great light into it for you... ;)
It sounds like you need jQuery for this.
You can wrap the rendered partial in a parent div with a hide class. When the button is clicked toggle displaying the content.
http://api.jquery.com/show/
$('#your-button').click(function(e){
$('.hidden-div').toggleClass('hide');
});
There are two ways to do this.
Firstly, if you're wanting to load the JS on-page, you need to use what #anchalee suggested, and preload the content with some sort of "hide" class in the CSS:
#app/assets/javascripts/application.js
$(document).on("click", "a.hidden", function(e){
e.preventDefault();
el = $(this).attr("href");
$(el).toggle();
});
#app/views/controller/your_view.html.erb
<%= link_to "User", "#user", class: "hidden" %>
<div id="user" class="hidden">
Hello
</div>
This will take any divs with the id specified by the href attribute of the link, and then make it so that the div will hide or show depending on its current state.
--
Secondly, you have the off-page method (using ajax).
This is used to get data from the server, and will be where you'd load server-centric data such as what you're trying to do now.
Doing this is actually quite simple:
#app/controllers/your_controller.rb
class YourController < ApplicationController
layout: Proc.new{|c| !c.request.xhr? }
end
This will return any data you need without the layout:
#app/assets/javascripts/application.js
$(document).on("click", "#show", function(e){
e.preventDefault();
$.get($(this).attr("href"), function(data){
$("#show").html(data);
});
});
#app/views/your_controller/show.html.erb
<%= link_to "Show", [[url for page]], id: "show" %>

Loading a list of controllers dynamically

I can't get my head wrapped around solving the following problem using angularJS.
I have a list view containing different kinds of data elements. Each element in itself is a view and has its own controller.
Now I want to iterate over this Array of the data items and based on recordType attribute, I want to initialize a controller with a template and finally add it to the list view.
At the moment I am using ng-include="item.recordType+'.html'" to dynamically load the template and the template itself has an ng-controller tag which loads the relevant controller. But I am not sure if this is the best approach.
<div class="data-item" ng-repeat="item in container.record_collection">
<div ng-include src="item.tRecordType + '.html'"></div>
</div>
Say record-type is apples
<script id="apples.html" type="text/ng-template">
<div ng-controller="ApplesController as apple">
<!-- ... HTML TEMPLATE ... -->
</div>
</script>

rendering a html.erb in rails with javascript

I create a page and some parts of it are layout files that are rendered. However I want to render one of these rendered part again with javascript code.
I want to render these part again
<div id="dialog" title="Bookmark Folders" style="resize: both;">
<%=render "layouts/filetree.html.erb"%>
</div>
It render function creates this:
<div id="accordion">
<% #user.folders.each do |f| %> <h3 id="<%= f.folder_name%>" class="folderBar"><b id="folderName"><%= f.folder_name%></b> created <%=distance_of_time_in_words(f.created_at, Time.now)%> before</h3>
<div class="<%= f.folder_name.delete(" ")%>">
<%if f.docs.empty?%>
<b>-No document currently!-</b>
<%else%>
<% f.docs.each do |r|%>
<%= r.title%><br/>
<b><%=r.url%></b><br />
<%= r.snippet%><hr/>
<%end%>
<%end%>
</div>
<%end%>
</div>
Because after some execution there are some changes over "folders", I want to render this part again to see the update.
You shouldn't attempt to render erb with javascript - it's not how it's done (not to mention you'd have to write yourself a erb parser and eventually call the server for data anyway).
If on the other hand, you're asking how to issue the render of some template using Javasript and then replace old content with new one then...
Watch this http://railscasts.com/episodes/205-unobtrusive-javascript,
read this Rails 3 and RJS to get the idea of how to trigger some content updates via javascript.
General idea is
Render the initial full page
Trigger ajax call (either after some time or by manual user request) to do a request to your rails application
Handle that request and respond to it with javascript script (the script content should contain all the functionality and content to replace what you want)
It's possible to share templates between the server and the client. One library that allows for this is called mustache.
But if this is the only case you need it I'd go with the RJS approach as well.
Instead of rendering I did it AJAX way and update it on the page. Thanks for the answers but I did not use any of these.

Categories

Resources