A user should be able to design a room (room is a model) in my Rails app. When the user visits myapp.com/room/1 the room with its content and specific design is shown.
The design or CSS of the room is based on room parameters (color1, color2, ...) and some random generated design characteristics (font type, image border, ...). These characteristics are stored in the room model when the room is saved.
I don't see how I can generate a specific CSS for each room. When the user visits myapp.com/room/1 my app should build specific CSS (or SCSS) for room1. Where (what controller) should I build that CSS?
Thanks
You can make your RoomsController respond to the CSS format as well in order to get this to work:
# app/controllers/rooms_controller.rb
class RoomsController
def show
#room = Room.find(params[:id])
respond_to do |format|
format.html
format.css
end
end
end
Then you need to implement a template to be rendered for the CSS format:
/* app/views/rooms/show.css.erb */
.room {
background-color: <%= #room.color1 %>;
color: <%= #room.color2 %>;
}
Note how this is very similar to a regular template. You need to make sure that this results in valid CSS.
You need to make sure the stylesheet is included when the user visits the page. Let's say a user can browse their room design when they visit /rooms/1. This will render a HTML template, which we could define as follows:
<!-- app/views/rooms/show.html.erb -->
<% content_for :stylesheet_includes do %>
<%= stylesheet_link_tag(room_path(#room, format: :css)) %>
<% end %>
<div class="room">
Room Contents Here
</div>
Notice that I've used content_for around the stylesheet link tag. We can use this to make sure the stylesheet link tag is rendered nicely in the head of the layout:
<!-- app/views/layouts/application.html.erb -->
<head>
<%= yield :stylesheet_includes %>
</head>
Of course you'll need to fill in the details yourself, but this would be the most logical approach for the problem.
If you design your controller to respond to the show action with json requests, you'll be able to retrieve the attributes of the Room object in json format
http://localhost.com:3000/rooms/1.json
{"id":1,"color1":"black","color2":"green","created_at":"2014-12-15T19:52:21.235Z","updated_at":"2014-12-15T19:52:21.235Z"}
In that case, you can use javascript to make the get request, retrieve the data in JSON, and subsequently use that data to manipulate the dom.
$.get( "rooms/1.json", function( data ) {
alert(data);
});
Related
By default, rails has controller CRUD actions with corresponding routes. For instance, I have a simple bookstore app, where I have a book and category. I want to display all categories through a sidebar on a home page. Each category is a dropdown element accompanied with a books count integer. When expanding a dropdown I want to see a book title that belongs to a current and acts as link. That is easy to implement.
The question is how can I add a form hidden under, let's say a + sign, sticked next to a static Dropdown section title "Categories" if there are none?
A form for Create action in Category controller which would allow to create a new category and display it straight away without redirecting to Create category view and redirecting back.
Please advise any reliable solution or tutorial link. Thanks a lot.
It looks like you are looking for an AJAX form. In rails you can generate this with form_for ... remote:true. This can call a controller method with out refreshing the page. You can then return a response and use JS to update the page the user is on.
For example, in your view
<div class="hidden">
<%= from_for #category, remote:true %>
Your form here
<% end %>
</div>
Add in some JavaScript to un-hide the form when your button is clicked. In your controller
def create
#normal create stuff
if save
respond_to do |f|
f.js
f.html {#re render page just in case JavaScript is disabled}
end
else
#handle error
end
end
using the rails default f.js, Rails will call a file create.js.erb this file will have access to any public variable you make, for instance #category.
you can then do somthing along the lines of
$('.append_category').append('<%= j render 'your category layout partial', locals: { category: #category }%>');
or if you just need the category link
$('.append_category').append('<%= link_to #category %>');
A very nice guide can be found here http://guides.rubyonrails.org/working_with_javascript_in_rails.html
Note: depending on your version of rails, you may need to add include ActionController::MimeResponds to your application_controller.rb (I know this is required in rails 5)
Could it possible to put element in if function in ASP.NET like in ASP.NET MVC Razor view?
Maybe something like this :
<% if (Visible)
{
<div>I want to determine here</div>
} %>
But this will show error... I knew it could solve by using javascript or div with codebehind:
<div style="<%=isNotGame? "display:none":"display:block" %>"></div>
or:
<div runat="server" id="codeBehind"></div>
CodeBehind.InnerHTML="...";
Q1: Is it possible? If yes, how?
Q2: Why I want to do this is because I think if I don't want to show an element, it is better not to create the element than create and hide it, is it correct?
Yes it is possible, try this instead.
<%
if (Visible)
{
%>
<div>I want to determine here</div>
<%
}
%>
The 2nd question, in my opinion if you don't need it then there is no reason to take up the resources. Keep in mind that this is all data transferring over the wire. Depending on how many wasted elements you create it can add up fast and depending on what you are doing it may have a number of adverse affects. Many people pay for data on mobile devices. Search engines could penalize you for performance losses due to high volumes of data you never cared to send anyway.
As your original question says about razor syntax, it can be done as -
#if (Visible) {
<div>I want to determine here</div>
}
If you want more information on razor syntax, Check this
Answer to your question 2 is tricky. You can render whatever elements you want and take decision at code behind but if you want to toggle some elements by specific conditions of your scenario then it is better to do it by Javascript as for toggling requesting server to do it for client is bad approach.
It is possible to generate HTML in your razor view, as per your condition
#if(condition){
<div>show this div</div>
}
And about Question2, do not render unnecessary . But in case you need that HTML to be made visible depending on user actions, then render the HTML, use CSS to hide the same. And then on client side you can make it visible.
I have two nav bars, one for the home page, and one for the rest of the site. I'm not sure how to go about doing this in a good DRY way. It seems like i want to put the rest of the sites navbars in the layouts views, but I don't know how to exclude a layout from a page I guess? The rest of the home page layout is the same as the rest of the site, so the only thing I would want to exclude is the nav bar for that page and replace it with another. The links will also be the same. So navigation_links can also be rendered in both.
There are multiple solutions to this problem, but the one I like most is taking advantage of Rails' Template Inheritance. Let's say your home controller looks like this:
class HomeController < ApplicationController
end
Rails looks up the layout for the views rendered by this controller by its name, home. If there's no such layout, it will look for one named after its super class, application and so on. This is explained in the Rails documentation.
Looking up partials actually works the same way. Let's say you were to render a partial navigation_bar in your layout:
render 'navigation_bar'
If you don't specify its exact location (like application/navigation_bar, Rails will again use template inheritance to look for the partial.
So first it will look for home/navigation_bar, and then for application/navigation_bar. You can use this to your advantage if you only want to display a different navigation bar, without redefining the layout or anything else.
So you need to place your general navigation bar in application/_navigation_bar, and your home navigation bar in home/_navigation_bar. Then render the navigation bar in your layout:
render 'navigation_bar'
Use the content_for helper method.
In your view template, perhaps application.html.erb, you can do:
<% if content_for? :nav %>
<%= content_for :nav %>
<% else %>
<%= render 'layouts/nav' %>
<% end %>
Then in your home page:
<% content_for :nav, render('layouts/custom_nav') %>
Personally, I prefer this method—it's declarative, it lets others (including future you) know explicitly that the default nav can be overridden.
I have a lot of different webpages, but most fall into 1 of 6 or 7 categories of pages. For each of these categories of webpages, I have a slightly different look and feel, like different background colors/images. I have the following in views/layout/application.html.erb:
<header class="sub<% if content_for?(:page_type) %> <%= yield(:page_type) %><% end %>">
And in every single view, I have:
<% content_for :page_type, 'information' %>
But it's really a pain to do that for every single webpage and when I want to change things around I keep having to mess with these (I have a ton of pages). So, instead I'm thinking to just use a variable:
<header class="sub<%= #page_type ? ' ' + #page_type : '' %>">
and for views:
<% #page_type = 'information' %>
The advantage is I could do a before_filter :set_page_type in the controller and set the page type once for all the views it controls (a big help).
Maybe the best thing for me to do is just use the first folder of the URL as the category of the webpage. I'll have to restructure the URLs, but that might make sense to do so anyway. I do have some top-level pages that would have to remain so.
This has to be a fairly common situation, what is the best way to categorize most pages and use that categorization in layouts?
I’m usually using a helper for the body class — something like this:
def body_class(c = nil)
#body_class ||= [controller.controller_name]
#body_class << c
#body_class.flatten.compact.uniq.join(" ")
end
This will by default include the controller name (you could also include the action etc..
Then I call this helper in views as needed, e.g.
<% body_class "bar" %>
Since the helper always returns a class string, you can then call the same helper in you layout (I use the body tag), likely without arguments:
<body class="<%= body_class %>">
Which would render in the previous example for a controller called FoosController the following:
<body class="foos bar">
If you define the helper in e.g. the application controller and make it available to the views using helper_method, this should hopefully much do what you’re after.
I have a partial view (.ascx) that should include its own CSS file as it's used in multiple other views. How do I inject a stylesheet in the page server-side, i.e. without using JavaScript?
Dario - due to using this for partialviews, you're going to always have the problem that the <head> section of the document is already in place and therefore can't be modified. If you want to remain WC3 compliant, then you'll have to put any further css into the head section via javascript. This may or may not be desirable (if you've got to cater for downsteam browsers with javascript turned off).
the main problem that you may be aluding to is the fact that you can't put <asp:contentplaceholders> into your partials. this is a pain (tho understandable as the masterpage ref would tie the partial too closely to a particular master page).
To this end, I've created a little helper method that does the basic grunt work to put the css file into the head section automatically.
edit - (as per Omu's js suggestion) this is a nice little halfway house:
// standard method - renders as defined in as(cp)x file
public static string Css(this HtmlHelper html, string path)
{
return html.Css(path, false);
}
// override - to allow javascript to put css in head
public static string Css(this HtmlHelper html, string path, bool renderAsAjax)
{
var filePath = VirtualPathUtility.ToAbsolute(path);
HttpContextBase context = html.ViewContext.HttpContext;
// don't add the file if it's already there
if (context.Items.Contains(filePath))
return "";
// otherwise, add it to the context and put on page
// this of course only works for items going in via the current
// request and by this method
context.Items.Add(filePath, filePath);
// js and css function strings
const string jsHead = "<script type='text/javascript'>";
const string jsFoot = "</script>";
const string jsFunctionStt = "$(function(){";
const string jsFunctionEnd = "});";
string linkText = string.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\"></link>", filePath);
string jsBody = string.Format("$('head').prepend('{0}');", linkText);
var sb = new StringBuilder();
if (renderAsAjax)
{
// join it all up now
sb.Append(jsHead);
sb.AppendFormat("\r\n\t");
sb.Append(jsFunctionStt);
sb.AppendFormat("\r\n\t\t");
sb.Append(jsBody);
sb.AppendFormat("\r\n\t");
sb.Append(jsFunctionEnd);
sb.AppendFormat("\r\n");
sb.Append(jsFoot);
}
else
{
sb.Append(linkText);
}
return sb.ToString();
}
usage:
<%=Html.Css("~/Content/yourstyle.Css")%>
or:
<%=Html.Css("~/Content/yourstyle.Css", true)%> // or false if you want!!
worth a back-pocket approach if all else fails. it may also be possible to adapt the logic above to hit an actionfilter and add the css to the reponse headers etc.., rather than outputting the js string.
Is there a reason you cannot just put the stylesheet in the main view page? Unless it is extremely large, it should not cause your page to load significantly slower when not being used, especially after compression.
Furthermore, if the partial view is being retrieved by ajax, you will end up re-downloading the css file multiple times (depending on the browser's caching).
I'm not an ASP.NET or MVC expert, but I am currently working on a project with it. Would it be possible to include something like this in the head of your master page?
<asp:ContentPlaceHolder ID="HeadContent" runat="server"></asp:ContentPlaceHolder>
Then somehow get your CSS into the content placeholder?
<asp:Content ID="styleSheetHolder" ContentPlaceHolderID="HeadContent" runat="server">
<link rel='stylesheet' href='yourstyle.css' type='text/css' />
</asp:Content>
It looks like you'd have to do this from the calling page, which would introduce duplication of code. I'm not sure how to get around that. Maybe it could it be done with an HTML helper.
A place I worked had a site with a lot of conditional partial views, which could and would change from time to time as new things were added to the application. The best way we found was to use naming conventions - naming the partial view, stylesheet and script the same (except extension, of course).
We added one or more stylesheets, scripts and partial views to the page's view model. We then used a custom HTML helper to loop through the relevant array in each content section and insert the required content. The pain was having to manage three or more files for each component, but at least we were able to reduce the amount of maintenance in the hosting pages.
Never did resolve the problem of putting a partial view inside a partial view, though.
Why not put the link tag in your partial view:
<link rel="stylesheet" href="yourstyle.css" type="text/css" />