I was researching here on SO how to implement a tabbed interface in my Rails app. For example, I like how Ryan Bates uses it in his Railscast overview page.
I want to mimic that in my Rails app so that a User's profile has a navigation in it with two or three links. Clicking either link loads information using AJAX (I'm guessing). Then the URL shows /profiles/1/view?info or /profiles/1/view?otherdata
I came across this question, with the following solution:
I would make the contents of each tab be called in by a separate ajax request. This would give you the following benefits
Now each tab can easily be a different view/controller
You only need to load the contents for a tab when it is used; you won't be processing code/downloading html for tabs that the user doesn't use.
The problem is I'm new to Rails and have no idea how to do this. Can anyone point me to some resources that help explain how to set this up? I'd be tabbing between profile data and messages to the user.
Any help would be much appreciated.
As you're new to Rails I'd suggest breaking up your goal into 2 sections: first, get the tabs working with simple content, then add the AJAX.
Step 1 - Getting the tabs working
Have a look at the JQuery UI tabs demos: http://jqueryui.com/demos/tabs/
The code looks something like this:
<div id="tabs">
<ul>
<li>Nunc tincidunt</li>
<li>Proin dolor</li>
<li>Aenean lacinia</li>
</ul>
<div id="tabs-1">
<p>Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus.</p>
</div>
<div id="tabs-2">
<p>Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc.</p>
</div>
<div id="tabs-3">
<p>Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem.</p>
<p>Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque.</p>
</div>
</div>
<script>
$(function() {
$( "#tabs" ).tabs();
});
</script>
Step 2 - Getting the AJAX working
Check out: http://jqueryui.com/demos/tabs/#ajax
Even it may be hip to use AJAX today, why not do the Simplest Thing That Could Possibly Work? If have done in the past something like the following:
Adding tabs to the UI by code like the following (notation is HAML, sorry for that). As a result, you get a list of links that link to the controllers index action. This code is part of the file layouts/_header.html.haml.
%ul.sideul
- ["page", "notice", "contact"].each do |thing|
- curr = controller.controller_name.singularize == thing
- cl = curr ? 'current' : 'normal'
%li.normal= link_to(thing.humanize, {:controller => controller, :action => "index"}, {:class => cl })
Add then the CSS to your application that this is shown as tabs. There you will need the information if a li is current or normal.
Every time you click then on the tab, the index action of that controller is called, and after that, the index page is shown.
Your file layouts/application.html.haml should have the following content (at least). I have skipped what is not necessary for the example. The template is taken from html5-boilerplate for Rails.
%body{ :class => "#{controller.controller_name}" }
#columns
%header#side
= render "layouts/header"
#main{ :role => 'main' }
%h1= yield(:title)
= render "layouts/flashes"
= yield
= render "layouts/javascripts"
The relevant parts for this solution is:
= render "layouts/header": Renders the list of tabs inside of #columns > header#side
= yield: Renders whatever is in the view for the action of the controller. In our case first the index page, may be later the edit or show page.
Related
For context, I'm running a gatsby site with MDX enabled and I can't for the life of me, figure out how to get the URL to a Lottie JSON animation in the same folder as the MDX file (different from /src/pages/).
I'm not using templates other than rendering every page in the same component using gatsby-browser. The is defined as part of the component and the lottie-player library is included as part of the head.
Here's what I've defined the MDX file as -
---
title: Sample file
slug: /sample
order: 3
type: work
published: true
lastUpdatedDate: September 29, 2022
currentVerion: v2.0.0
excerpt: Sample excerpt text
roles:
- Product Manager
- Product Designer
specialUrl: /blog/foo
coverUrl: ./hero.json
headshot: ./headshot.jpeg
---
export const Head = (props) => <title>{props.pageContext.frontmatter.title + `- Portfolio`}</title>
import { BodyText } from "../../../components/Type"
import { PrimaryButton } from "../../../components/Button"
import HeadshotImg from "./headshot.jpeg"
# Sample project file
<BodyText>{props.pageContext.frontmatter.coverUrl.publicURL}</BodyText>
<BodyText>{props.pageContext.frontmatter.excerpt}</BodyText>
<lottie-player src="/static/23c130bba09d98c90f21287dfc6a9b1c/hero.json" background="transparent" speed="0.5" loop autoplay></lottie-player>
<img src={HeadshotImg} />
<PrimaryButton>Okay so this works</PrimaryButton>
Nihil accusantium aut assumenda est sed[^1]. Enim et eum corporis qui. Modi error laboriosam rerum recusandae impedit voluptate aut distinctio magni. Dolorem voluptatem sit non temporibus quibusdam ipsum. Accusantium voluptatem ut eaque numquam qui numquam est iste.
Voluptate consequatur soluta animi necessitatibus temporibus. Incidunt itaque magni. Eos quisquam similique dolorum occaecati accusantium. Quia voluptatum voluptatem laborum id odit est.
Cum ut non illum est nam ut magni totam. Voluptatibus voluptas magnam mollitia non ut est itaque harum. Et facilis at.
[^1]: Big note.
In the same folder as this MDX file, I've included hero.json. Using a graphQL query, I was able to determine the publicURL underneath the coverUrl object in the schema and included it explicitly here and the lottie renders correctly -
<lottie-player src="/static/23c130bba09d98c90f21287dfc6a9b1c/hero.json" background="transparent" speed="0.5" loop autoplay></lottie-player>
However, I'm not able to use props.pageContext.frontmatter.coverUrl.publicURL directly. This code doesn't display anything. Upon inspecting, there's nothing in between the <p> tags. (BodyText extends the p markup)
<BodyText>{props.pageContext.frontmatter.coverUrl.publicURL}</BodyText>
I tested the excerpt (next line between the <BodyText> tags) and it works correctly too.
What am I missing that the string response retrieved from the graphQL query is good enough for the Lottie src, but when used as a query directly as I do for other frontmatter objects, it doesn't render?
I feel I'm missing something really obvious, but it's taken me 4 hours of trying a lot of things but not getting anywhere. Many thanks in advance!
When I type
<font> test </font>
in laravel blade file nothing is rendered in chrome.
Edit: please dont just advise not to use font tag, read the whole question. This font tag is generated by wysiwyg editor summernote so its not my choice to use it or not.
Weird thing is that I see this tag in page source but its not rendered on the page. When I make local html file with same source - it shows text within font tags in Chrome.
Also when I go to developer tools elements and click on container div to edit as html, if I add anything anywhere, then all the font tags suddenly show up. Behavior is exactly the same in Firefox. If I dont edit page in inspector font tags are not shown no matter how many times I refresh.
here is my blade file:
#extends('layouts.app')
#section('content')
<font> test </font>
<p> <-Back</p>
<p> Selected article: {{$article->title}} </p>
<p> Description: {{$article->description}} </p>
<p><img src="/{{$article->image}}" width="600px" alt="ASD"></p>
<font> ojo </font>
{!! $article->body !!}
<p>ge?</p>
#stop
The <font></font> was deprecated in HTML 4.01 at the same time as all elements related to styling only, then obsoleted in HTML5.
This has nothing to do with laravel.
The former behavior of the <font> element can be achieved, and even better controlled using the CSS Fonts CSS properties
See more information on <font> here.
EDIT
I got your question wrong, http://summernote.org/ is generating the <font> tag. You could replace it every time the summernote gets input. Like this:
(May need some adjustments)
//some dynamic elements have to be triggered from the body
$body = $(document.body);
//container where font excists
$container = $('.container')
//less code to type
function observe(element, event, handler) {
$body.on(event, element, handler)
}
//delay 0 to speed up
function delay_func() {
window.setTimeout(font_to_span(), 0);
}
//replace font tags with span and extract the font family
function font_to_span() {
$font = $container.find('font');
font_family = $font.attr('face');
$font.replaceWith(function() {
return $("<span />", {
html: $(this).html(),
style: 'font-family:' + font_family + ';'
});
});
}
//add events to trigger font finder_to_span on
observe($container, 'change', font_to_span);
observe($container, 'cut', delay_func);
observe($container, 'paste', delay_func);
observe($container, 'drop', delay_func);
observe($container, 'keydown', delay_func);
font_to_span();
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<div class="container">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce feugiat, sapien sed tempor dignissim, mi metus tempor enim, <font face="Comic Sans MS">a vestibulum nulla tortor</font> posuere tellus. Etiam eu dolor ut dui viverra dictum non non justo. Duis
blandit in enim vitae mollis. Integer euismod lectus ut turpis fermentum, eget rutrum urna ornare.</div>
I found what was causing this behavior, I should have realized earlier that if it looks like magic - its javascript.
So in basic Laravel 5.3 blade page we have font tags in the source and we can see it in page source on frontend but they are not visible on page. Reason is because Laravel 5.3 by default includes Vue javascript framework by including app.js that includes Vue, which runs some Vue magic on document load, so font tags are being hidden for some reason - probably related to being deprecated.
I removed Vue from my Laravel app for now (by removing js code that includes it) and font tags are back.
I need to load data from database to create a menu, how can I pass the data to a Ajax request, need a Ajax Request? When I click in the menu, will load just the link that was click in the tab-pane, not all 3, I didn't find anything about this specific subject:
<ul class="nav nav-tabs">
<li class="active">Home</li>
<li>Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
</ul>
<div class="tab-content">
<div id="home" class="tab-pane fade in active">
<h3>HOME</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
<div id="menu1" class="tab-pane fade">
<h3>Menu 1</h3>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
Example with php:
Dynamic Bootstrap Tabs using PHP/MySQL
http://www.99logic.com/how-to-create-dynamic-tab-using-ajax-jquery-in-php/
This works pretty much in the same way as the PHP links you referenced, since it is a mostly client-side solution.
The base page that loads in the browser needs to have the overall tab structure. In this page you'll have to handle click events to the tabs. On each of the tab's click handler you will issue an ajax call to retrieve the corresponding HTML from the server. The URLs for these endpoints could be, for example, /menu1, /menu2, and so on. The Flask server defines these endpoints and returns the content of each tab in them. You can have these defined as Jinja2 templates if you like. The Ajax request in the client will have a completion callback, and in there you will take the HTML that came from the request and insert it in the tab's body. For everything except the server-side endpoints you can take the code from the PHP solutions, that should all work the same.
Hope this helps!
I've created a layout with Maqetta. Now I want to add the logic to the layout. Therefore I have downloaded the whole workspace from Maqetta and imported the files/libaries into a new Rails project. At first I had some problems, that Rails didn't loaded the dojo,js file, but I've solved that problem.
Now I have another problem. The page won't render. I've commented everything out except one widget (a button) and this works fine. But if I undo this, nothing happens. Unfortunately I also don't get any warnings/errors or anything like that from dojo.
After a little bit trying, I changed the parseOnLoad property and now I get a warning:
Unhandled Error: Tried to register widget with id==appLayout but that id is already registered
Here is the include tag:
<%= javascript_include_tag "lib/dojo/dojo/dojo", :'data-dojo-config' => "'async':true,
'packages':[{'name':'maqetta','location':'../../maqetta'},{'name':'gridx','location':'../gridx'},{'name':'clipart','location':'../../clipart'},{'name':'shapes','location':'../../shapes'},
{'name':'maqettaSamples','location':'../../../samples'},{'name':'zazl','location':'../../zazl'},{'name':'widgets','location':'../../custom'}]" %>
Here is the HTML part (I have simplified it, and now I'm just useing the example from the tutorial):
<body class="claro" data-maq-flow-layout="true" data-maq-ws="collapse" id="myapp" data-maq-appstates="{}">
<input type="button" data-dojo-type="dijit.form.Button" intermediateChanges="false" label="Search" iconClass="dijitNoIcon" onclick="alert('hi');"></input>
<div
id="appLayout" class="demoLayout"
data-dojo-type="dijit/layout/BorderContainer"
data-dojo-props="design: 'headline'">
<div
class="centerPanel"
data-dojo-type="dijit/layout/ContentPane"
data-dojo-props="region: 'center'">
<div>
<h4>Group 1 Content</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
<div>
<h4>Group 2 Content</h4>
</div>
<div>
<h4>Group 3 Content</h4>
</div>
</div>
<div
class="edgePanel"
data-dojo-type="dijit/layout/ContentPane"
data-dojo-props="region: 'top'">Header content (top)</div>
<div
id="leftCol" class="edgePanel"
data-dojo-type="dijit/layout/ContentPane"
data-dojo-props="region: 'left', splitter: true">Sidebar content (left)</div>
</div>
And here is the parser:
require(["dojo/parser","dojo/domReady!"], function(parser){
parser.parse();
});
I'm trying for hours now, and I'm still as clueless as at the beginning. Has somebody an idea what I can try?
Unhandled Error: Tried to register widget with id==appLayout but that id is already registered
This error is because you are parsing twice. Once on load and second in the require statement. The second parse will try registering a second widget with the same id, thus the error.
Remove one of the parsing calls and give the border container a specific width and height.
<div id="appLayout" class="demoLayout"
data-dojo-type="dijit/layout/BorderContainer"
data-dojo-props="design: 'headline'"
style="width: 800px; height: 400px">
See http://livedocs.dojotoolkit.org/dijit/layout/BorderContainer#setting-sizes, the closest parent for which hasLayout is true (e.g. position:relative) must have a width+height set. Also, set width+height for BorderContainer.
In my cshtml files I have a lot of blocks with stuff like this:
#if(Model.foo)
{
<span>Hello World</span>
}
The only reason the span is there is because I can't find any other way to force it to recognize that "Hello World" is part of the html unless I surround it in html tags. Is there a good way to escape the code that doesn't involve adding meaningless tags to the display?
You could use #: to escape:
#if(Model.foo)
{
#:Hello World
}
or the special <text> tag which is not outputted in the response:
#if(Model.foo)
{
<text>Hello World</text>
}
#if(Model.foo)
{
#:Hello World
}
<text>Explicit HTML<text>
#(Explicit C#)
You can add text in as below:
#if(Model.foo)
{
#:Hello World
}
when you use # razor switch it to code block mode. Hence you need to specify text as above.
many developers has provided many ways above .. here is one more which is working fine in MVC 4 .. I hope it will work for MVC 3 also ..
#if(Model.foo)
{
#Html.Label("Hello World")
}
The above answers are great. I'm going to include a link to Scott Guthrie's article on this, since it shows some more examples and explanations.
https://weblogs.asp.net/scottgu/asp-net-mvc-3-razor-s-and-lt-text-gt-syntax
#if (p.UnitsInStock == 0 {
<text>
Donec in ante vitae purus consequat laoreet ut elementum
purus. Ut ut tempus nulla, quis ultrices est. Integer
pharetra ante in lectus porta, a lacinia ex faucibus.
Aliquam magna risus, pretium vel neque at, laoreet
ultrices lectus. Morbi posuere luctus risus. Nullam
tincidunt massa egestas nunc tempor scelerisque.
</text>
}
#if (p.UnitsInStock == 0 {
#: Line 1
#: Line 2
#: Line 3
}