I am trying to embed an R htmlwidget into an existing webpage -- a webpage that already has bootstrap and styling applied. For example, consider the following webpage (note where the widget should be placed):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>This is a test.</p>
<!-- htmlwidget should go here. -->
<p>A closing paragraph.</p>
</body>
</html>
I can create and save a datatable widget like so:
library(htmlwidgets)
library(datatable)
d1 <- datatable(mtcars, filter = "top")
saveWidget(d1, file = "widget_file.html")
The generated widget_file.html (even for this modest widget) contains a lot of code. Is there an easy way to embed this into an existing webpage/template?
I have been successful using <iframe src="widget_file.html"> but I'm wondering if there is a better way? Moreover, is there a way to separate pieces/dependencies (e.g. json data) from the widget_file.html so they can be placed in other folders?
Note: I created the htmlwidget tag, but I believe there should be a synonymous htmlwidgets tag.
The htmlwidget-Package offers a way to save the pieces for the widget separately as follows:
library(dygraphs)
d1 <- dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector(dateWindow = c("1920-01-01", "1960-01-01"))
saveWidget(d1, file = "widget_file.html", selfcontained = FALSE)
Which results in the following files/dirs:
widget_file.html
widget_file_files
/dygraphs-1.1.1
..
/dygraphs-binding-0.6
..
/htmlwidgets-0.5
..
/jquery-1.11.1
..
/moment-2.8.4
..
/moment-timezone-0.2.5
..
And widget_file.html reads as follows:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="widget_file_files/htmlwidgets-0.5/htmlwidgets.js"></script>
...
<script src="widget_file_files/dygraphs-binding-0.6/dygraphs.js"></script>
</head>
<body style="background-color:white;">
<div id="htmlwidget_container">
<div id="htmlwidget-2956" style="width:960px;height:500px;" class="dygraphs"></div>
</div>
<!-- THE JSON DATA -->
<script type="application/json" data-for="htmlwidget-2956">
{THE JSON DATA YOU WERE LOOKING FOR}
</script>
<!-- THE JSON DATA -->
<script type="application/htmlwidget-sizing" data-for="htmlwidget-2956">{Widget-Styling-Json}
</script>
</body>
</html>
So you can edit your html as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- Begin of scripts to run the widget -->
<script src="widget_file_files/htmlwidgets-0.5/htmlwidgets.js"></script>
<script src="widget_file_files/jquery-1.11.1/jquery.min.js"></script>
<link href="widget_file_files/dygraphs-1.1.1/dygraph.css" rel="stylesheet" />
<script src="widget_file_files/dygraphs-1.1.1/dygraph-combined.js"></script>
<script src="widget_file_files/moment-2.8.4/moment.js"></script>
<script src="widget_file_files/moment-timezone-0.2.5/moment-timezone-with-data.js"></script>
<script src="widget_file_files/dygraphs-binding-0.6/dygraphs.js"></script>
<!-- End of scripts to run the widget -->
<!-- Begin Widget styling -->
<script type="application/htmlwidget-sizing" data-for="htmlwidget-2956">{"viewer":{"width":450,"height":350,"padding":10,"fill":true},"browser":{"width":960,"height":500,"padding":40,"fill":true}}</script>
<!-- End widget Styling -->
<!-- Begin Data for the widget-->
<script type="application/json" data-for="htmlwidget-2956">{"x":{"attrs":{"title":"New Haven Temperatures","labels":["year","V1"],"legend":"auto","retainDateWindow":false,"axes":{"x":{"pixelsPerLabel":60}},"showRangeSelector":true,"dateWindow":["1920-01-01T00:00:00Z","1960-01-01T00:00:00Z"],"rangeSelectorHeight":40,"rangeSelectorPlotFillColor":" #A7B1C4","rangeSelectorPlotStrokeColor":"#808FAB","interactionModel":"Dygraph.Interaction.defaultModel"},"scale":"yearly","annotations":[],"shadings":[],"events":[],"format":"date","data":[["1912-01-01T00:00:00Z","1913-01-01T00:00:00Z","1914-01-01T00:00:00Z","1915-01-01T00:00:00Z","1916-01-01T00:00:00Z","1917-01-01T00:00:00Z","1918-01-01T00:00:00Z","1919-01-01T00:00:00Z","1920-01-01T00:00:00Z","1921-01-01T00:00:00Z","1922-01-01T00:00:00Z","1923-01-01T00:00:00Z","1924-01-01T00:00:00Z","1925-01-01T00:00:00Z","1926-01-01T00:00:00Z","1927-01-01T00:00:00Z","1928-01-01T00:00:00Z","1929-01-01T00:00:00Z","1930-01-01T00:00:00Z","1931-01-01T00:00:00Z","1932-01-01T00:00:00Z","1933-01-01T00:00:00Z","1934-01-01T00:00:00Z","1935-01-01T00:00:00Z","1936-01-01T00:00:00Z","1937-01-01T00:00:00Z","1938-01-01T00:00:00Z","1939-01-01T00:00:00Z","1940-01-01T00:00:00Z","1941-01-01T00:00:00Z","1942-01-01T00:00:00Z","1943-01-01T00:00:00Z","1944-01-01T00:00:00Z","1945-01-01T00:00:00Z","1946-01-01T00:00:00Z","1947-01-01T00:00:00Z","1948-01-01T00:00:00Z","1949-01-01T00:00:00Z","1950-01-01T00:00:00Z","1951-01-01T00:00:00Z","1952-01-01T00:00:00Z","1953-01-01T00:00:00Z","1954-01-01T00:00:00Z","1955-01-01T00:00:00Z","1956-01-01T00:00:00Z","1957-01-01T00:00:00Z","1958-01-01T00:00:00Z","1959-01-01T00:00:00Z","1960-01-01T00:00:00Z","1961-01-01T00:00:00Z","1962-01-01T00:00:00Z","1963-01-01T00:00:00Z","1964-01-01T00:00:00Z","1965-01-01T00:00:00Z","1966-01-01T00:00:00Z","1967-01-01T00:00:00Z","1968-01-01T00:00:00Z","1969-01-01T00:00:00Z","1970-01-01T00:00:00Z","1971-01-01T00:00:00Z"],[49.9,52.3,49.4,51.1,49.4,47.9,49.8,50.9,49.3,51.9,50.8,49.6,49.3,50.6,48.4,50.7,50.9,50.6,51.5,52.8,51.8,51.1,49.8,50.2,50.4,51.6,51.8,50.9,48.8,51.7,51,50.6,51.7,51.5,52.1,51.3,51,54,51.4,52.7,53.1,54.6,52,52,50.9,52.6,50.2,52.6,51.6,51.9,50.5,50.9,51.7,51.4,51.7,50.8,51.9,51.8,51.9,53]]},"evals":["attrs.interactionModel"]}</script>
<!-- End Data for the widget-->
</head>
<body>
<p>This is a test.</p>
<div id="htmlwidget_container">
<div id="htmlwidget-2956" style="width:960px;height:500px;" class="dygraphs"></div>
</div>
<p>A closing paragraph.</p>
</body>
</html>
This will leave you with the json-data hardcoded within the html-document (see my ).
If you want to load the data dynamically you can use e.g.
json_dat <- readLines("widget_file.html")[18]
cat(sub("</script>","",sub('<script type=\"application/json\" data-for=.*\">', "", json_dat)), file = "./widget_file_files/my_data.json")
To save the json-data as ./widget_file_files/my_data.json and then load it within the html. If you are using PHP you can do:
<script type="application/json" data-for="htmlwidget-2956">
<?php include('widget_file_files/my_data.json'); ?>
</script>
If you want to use a pure JS solution maybe have a look at http://api.jquery.com/jquery.getjson/ and the widget_file_files/htmlwidgets-0.5/htmlwidgets.js-File how the json-data is bound at the moment...
P.S.:
As this question got a lot of attention already you could also contact the package developer and ask him to further "un-selfcontain" the "selfcontained" option in htmlwidgets:::saveWidget: Meaning to save the json-data separately and include it e.g. via jquery.getjson
I face a problem when i try to use jqm in my website. A message of 'loading' appears on the bottom of my site. I figured out that it happens since I don't add jqm css. When I add the jqm css everything changes (color layout ect.). How is it possible to remove 'loading' message or add css without conflicts with the main css of my site?
<head>
<link href="css/site.css" rel="stylesheet" />
<!--<link href="css/jquery.mobile-1.3.2.min.css" rel="stylesheet" /> -->
<!-- disable loading msg -->
<script>
$(document).bind("mobileinit", function(){
$.mobile.loadingMessage = false;
});
</script>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"> </script>
<script src="scripts/jquery.mobile-1.3.2.min.js"></script>
</head>
I add script in my code. Nothing seems to happen! My problem solved only when i uncomment jqm css code, but then i got many conflicts with the site.css which i dont know how to solve.
To disable jQuery Mobile loading message, you need to override global settings once mobileinit triggers. The code should be placed in head after loading jQuery and before loading jQuery Mobile libraries.
<head>
<script src="jquery.js"></script>
<script>
$(document).on("mobileinit", function () {
$.mobile.loadingMessage = false;
});
</script>
<script src="jquery-mobile.js"></script>
</head>
I was implementing handlebar.js for my sample app.As per the handlebar.js documentation, it tried with the example as mentioned. But the values are loaded on the dom inside the script, but not visible on browser.
HTML
<body>
<h1>Handlebar</h1>
<script id="entry-template" type="text/x-handlebars-template">
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
</script>
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/handlebars.js"></script>
<script src="js/app.js"></script>
</body>
app.js
var source = $("#entry-template").html();
var template = Handlebars.compile(source);
var context = {title: "My New Post", body: "This is my first post!"}
var html = template(context);
$("#entry-template").html(template(context));
When the browser gets loaded i am getting a blank screen, but while debugging via firebug able to find the values title and body
You're replacing the content of a <script> element:
$("#entry-template").html(template(context));
and #entry-template is a <script>:
<script id="entry-template" type="text/x-handlebars-template">
Browsers don't display the content of <script>s with that type. You want to put your filled in template into something like a <div> that will be displayed:
<h1>Handlebar</h1>
<div id="html-goes-here"></div>
and then:
$("#html-goes-here").html(template(context));
My problem is I can't seem to use #RenderSection from a nested template when #RenderSection is defined in the base template. Currently, I have a nested base template which is linked to a child template which is then used in the view pages. When I define the #RenderSection in the base template and render it in the view pages it throws an error.
Here's the exact problem.
I want to create a RenderSection to allow me to insert custom scripts.
My base template....
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
#RenderSection("HeaderContent", false) // The region of the header scripts (custom css)
</head>
<body>
#RenderBody()
</body>
</html>
I then skip the child template as I do not want to put any custom head code in there and apply it to the page itself..
#section HeaderContent {
<script>alert("hi");</script>
}
My problem is that I cant seem to add custom head code in to the base template from my normal pages.
The following sections have been defined but have not been rendered for the layout page ~/Views/Shared/OneColLayer.cshtml": "HeaderContent.
Do I need to include a pointer to the base template in the view page?
#{
Layout = "~/Views/Shared/BaseTemplate.cshtml";
}
My new base template
<head>
<link rel="stylesheet" type="text/css" href="#Url.Content("~/content/layout.css")" />
<link rel="stylesheet" type="text/css" href="#Url.Content("~/content/global.css")" />
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/js/fadeInFadeOut.js")"></script>
<title>#ViewBag.Title</title>
#RenderSection("HeaderContent", false)
</head>
<body>
#RenderBody()
</body>
my new child template
#{
Layout = "~/Views/Shared/BaseTemplate.cshtml";
}
#RenderSection("HeaderContent", false)
#RenderBody()
my view
#{
ViewBag.Title = "Home";
Layout = "~/Views/Shared/OneColLayer.cshtml";
}
#section HeaderContent {
<h1>Left Content</h1>
}
<div>my view content</div>
the content gets placed in the oneCol template now the base template.
results...
<div id="Content">
<h1>Left Content</h1>
</div>
You need to specify the sections that are allowed to pass through in the middle template.
BaseTemplate.cshtml
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
#RenderSection("HeaderContent", false) #* The region of the header scripts (custom css) *#
</head>
<body>
#RenderBody()
</body>
</html>
EDIT
your new child template
#{
Layout = "~/Views/Shared/BaseTemplate.cshtml";
}
#section HeaderContent {
#RenderSection("HeaderContent", false)
}
#RenderBody()
If you put the render section inside of a section from the base template, it will render that section in the correct place on the base template.
View.cshtml -> uses MiddleLayout.cshtml as it's layout
#section HeaderContent
{
<!-- header content that will now render -->
}
<!-- page content -->