Friends,
I am trying to use DyGraph in my application. Please look at the code below -
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7; IE=EmulateIE9">
<title>crosshairs</title>
<script type="text/javascript" src="dygraph-combined.js"></script>
<script type="text/javascript" src="data.js"></script>
</head>
The code uses data.js file containing function to get some static data.
I want data.js to be generated using a controller method so that it will generate data using database.
Can anybody help me out to resolve this issue.
Thanks for sharing your valuable time.
You could define a controller action:
public ActionResult Data()
{
// Obviously this will be dynamically generated
var data = "alert('Hello World');";
return JavaScript(data);
}
and then:
<script type="text/javascript" src="<%= Url.Action("Data", "SomeController") %>"></script>
If you have some complex script that you don't want to generate in the controller you could follow the standard MVC pattern by defining a view model:
public class MyViewModel
{
... put required properties
}
a controller action which would populate this view model and pass it to the view:
public ActionResult Data()
{
MyViewModel model = ...
Response.ContentType = "application/javascript";
return PartialView(model);
}
and finally a view which in this case will be the javascript representation of the view model (~/Views/SomeController/Data.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<MyViewModel>" %>
alert(<%= new JavaScriptSerializer().Serialize(Model.Name) %>);
Full Disclosure
This answer is copy/pasted from another question:
Dynamically generated Javascript, CSS in ASP.NET MVC
This answer is similar to other answers here.
This answer uses cshtml pages rather than ascx controls.
This answer offers a View-Only solution rather than a Controller-Only solution.
I don't think my answer is 'better' but I think it might be easier for some.
Dynamic CSS in a CSHTML File
I use CSS comments /* */ to comment out a new <style> tag and then I return; before the closing style tag:
/*<style type="text/css">/* */
CSS GOES HERE
#{return;}</style>
Dynamic JS in a CSHTML File
I use JavaScript comments // to comment out a new <script> tag and then I return; before the closing script tag:
//<script type="text/javascript">
JAVASCRIPT GOES HERE
#{return;}</script>
MyDynamicCss.cshtml
#{
var fieldList = new List<string>();
fieldList.Add("field1");
fieldList.Add("field2");
}
/*<style type="text/css">/* */
#foreach (var field in fieldList) {<text>
input[name="#field"]
, select[name="#field"]
{
background-color: #bbb;
color: #6f6f6f;
}
</text>}
#{return;}</style>
MyDynamicJavsScript.cshtml
#{
var fieldList = new List<string>();
fieldList.Add("field1");
fieldList.Add("field2");
fieldArray = string.Join(",", fieldList);
}
//<script type="text/javascript">
$(document).ready(function () {
var fieldList = "#Html.Raw(fieldArray)";
var fieldArray = fieldList.split(',');
var arrayLength = fieldArray.length;
var selector = '';
for (var i = 0; i < arrayLength; i++) {
var field = fieldArray[i];
selector += (selector == '' ? '' : ',')
+ 'input[name="' + field + '"]'
+ ',select[name="' + field + '"]';
}
$(selector).attr('disabled', 'disabled');
$(selector).addClass('disabled');
});
#{return;}</script>
No Controller Required (using Views/Shared)
I put both of my dynamic scripts into Views/Shared/ and I can easily embed them into any existing page (or in _Layout.cshtml) using the following code:
<style type="text/css">#Html.Partial("MyDynamicCss")</style>
<script type="text/javascript">#Html.Partial("MyDynamicJavaScript")</script>
Using a Controller (optional)
If you prefer you may create a controller e.g.
<link rel="stylesheet" type="text/css" href="#Url.Action("MyDynamicCss", "MyDynamicCode")">
<script type="text/javascript" src="#Url.Action("MyDynamicJavaScript", "MyDynamicCode")"></script>
Here's what the controller might look like
MyDynamicCodeController.cs (optional)
[HttpGet]
public ActionResult MyDynamicCss()
{
Response.ContentType = "text/css";
return View();
}
[HttpGet]
public ActionResult MyDynamicJavaScript()
{
Response.ContentType = "application/javascript";
return View();
}
Notes
The controller version is not tested. I just typed that off the top of my head.
After re-reading my answer, it occurs to me it might be just as easy to comment out the closing tags rather than use the cshtml #{return;}, but I haven't tried it. I imagine it's a matter of preference.
Concerning my entire answer, if you find any syntax errors or improvements please let me know.
Related
I am using Thymeleaf as template engine. How I pass a variable from Spring model to JavaScript variable?
Spring-side:
#RequestMapping(value = "message", method = RequestMethod.GET)
public String messages(Model model) {
model.addAttribute("message", "hello");
return "index";
}
Client-side:
<script>
....
var m = ${message}; // not working
alert(m);
...
</script>
According to the official documentation:
<script th:inline="javascript">
/*<![CDATA[*/
var message = /*[[${message}]]*/ 'default';
console.log(message);
/*]]>*/
</script>
Thymeleaf 3 now:
Display a constant:
<script th:inline="javascript">
var MY_URL = /*[[${T(com.xyz.constants.Fruits).cheery}]]*/ "";
</script>
Display a variable:
var message = [[${message}]];
Or in a comment to have a valid JavaScript code when you open your template file in a static manner (without executing it at a server).
Thymeleaf calls this: JavaScript natural templates
var message = /*[[${message}]]*/ "";
Thymeleaf will ignore everything we have written after the comment and before the semicolon.
More info: http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#javascript-inlining
var message =/*[[${message}]]*/ 'defaultanyvalue';
According to the documentation there are several ways to do the inlining.
The right way you must choose based on the situation.
1) Simply put the variable from server to javascript :
<script th:inline="javascript">
/*<![CDATA[*/
var message = [[${message}]];
alert(message);
/*]]>*/
</script>
2) Combine javascript variables with server side variables, e.g. you need to create link for requesting inside the javascript:
<script th:inline="javascript">
/*<![CDATA[*/
function sampleGetByJquery(v) {
/*[+
var url = [[#{/my/get/url(var1=${#httpServletRequest.getParameter('var1')})}]]
+ "&var2="+v;
+]*/
$("#myPanel").load(url, function() {});
}
/*]]>*/
</script>
The one situation I can't resolve - then I need to pass javascript variable inside the Java method calling inside the template (it's impossible I guess).
MAKE sure you have thymleaf on page already
//Use this in java
#Controller
#RequestMapping("/showingTymleafTextInJavaScript")
public String thankYou(Model model){
model.addAttribute("showTextFromJavaController","dummy text");
return "showingTymleafTextInJavaScript";
}
//thymleaf page javascript page
<script>
var showtext = "[[${showTextFromJavaController}]]";
console.log(showtext);
</script>
I've seen this kind of thing work in the wild:
<input type="button" th:onclick="'javascript:getContactId(\'' + ${contact.id} + '\');'" />
If you use Thymeleaf 3:
<script th:inline="javascript">
var username = [[${session.user.name}]];
</script>
If you need to display your variable unescaped, use this format:
<script th:inline="javascript">
/*<![CDATA[*/
var message = /*[(${message})]*/ 'default';
/*]]>*/
</script>
Note the [( brackets which wrap the variable.
Another way to do it is to create a dynamic javascript returned by a java controller like it is written here in the thymeleaf forum: http://forum.thymeleaf.org/Can-I-use-th-inline-for-a-separate-javascript-file-td4025766.html
One way to handle this is to create a dynamic javascript file with the
URLs embedded in it. Here are the steps (if you are using Spring MVC)
#RequestMapping(path = {"/dynamic.js"}, method = RequestMethod.GET, produces = "application/javascript")
#ResponseStatus(value = HttpStatus.OK)
#ResponseBody
public String dynamicJS(HttpServletRequest request) {
return "Your javascript code....";
}
Assuming request attribute named "message":
request.setAttribute("message", "this is my message");
To read it in the html page using Thymeleaf template:
<script>
var message = "[[${message}]]";
alert(message);
</script>
i am relatively new to spring mvc.what i am trying to do is pass a variable as model attribute and try and access it on page load with javascript on my JSP page.
my java code is as follows
model.addAttribute("leagueCode",leagueCode);
model.addAttribute("league","new");
return "redirect:/Dashboard";
and on jsp side i am trying to access it by following
<script type="text/javascript"> function myFunction() { var leagueCode=${leagueCode}; alert(leagueCode); } </script> </head> <body onload="myFunction()">
but i am getting the value as blank. is this the right way i am following or is there any other way this has to be done? please help
In the JSP page you can set the values as javascript variables by adding a script tag in the <head> with the assignment inside as a json object for example:
<script>
var myServerSideVars = {
"aServerSideVarName" : "<here you set the value with el/jslt/scriptlet>",
"anotherServerSideVarName" : "<here you set the value with el/jslt/scriptlet>"
};
</script>
EDIT I
Example using EL (Expression Language) but the same could be done with scriptlets if you are using that (<% %>):
Lets say in your Servlet you put a Car instance in the request before forwarding to the JSP page.
The car:
public class Car{
protected String brand;
protected String year;
//getters and setters for the two properties.
}
In the Servlet you put it into the request:
Car car = new Car();
car.setBrand("BMW");
car.setYear("2017");
request.setAttribute("carInRequest", car);
In the JSP you set it to a Json Object accessible from javascript. Before closing the body tag I put a simple example of how the var can be accessed from javascript. I haven't run it so it may have some typo or error to correct:
<%#taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>System.out.println</title>
<script>
var aCar= {
"brand" : "${requestScope.carInRequest.brand}",
"year" : "${requestScope.carInRequest.year}"
};
</script>
</head>
<body>
<h2>Brand: <span id="brandPlaceHolder"></span></h2>
<h2>Year: <span id="yearPlaceHolder"></span></h2>
</body>
<script>
var brandSpan = document.findElementById("brandPlaceHolder");
brandSpan.html = aCar.brand;
var yearSpan = document.findElementById("yearPlaceHolder");
brandSpan.html = aCar.year;
</script>
</html>
I don't know how to use razor syntax in Javascript.
I want to make Html.ListBoxFor with items from my model. I used to use:
#Html.ListBoxFor(x => x.TagIdList, (MultiSelectList)ViewBag.Tags, new { #class = "chzn-select", data_placeholder = "Tags..." })
As you see I want also use chzn-select class, to have better layout.
For now, I just have this code above in HTML as plain text, but I want have there things from my model.
Any ideas?
There is my code in ASP.NET MVC:
#model Generator.Models.ExamModel
#{
ViewBag.Title = "Generate";
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="#Url.Content("~/Multiple_chosen/chosen.jquery.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/ListOfTags.js")" type="text/javascript"></script>
<script >
$(".chzn-select").chosen();
</script>
}
<link href="#Url.Content("~/Multiple_chosen/chosen.css")" rel="stylesheet" type="text/css" />
<h1>#ViewBag.Title</h1>
<h2>#ViewBag.Message</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Generate</legend>
<div class="editor-label">Numbers</div>
<div class="editor-field" id="NumberOfModels">
#Html.EditorFor(model => model.NumberOfQuestions)
</div>
<div class="editor-label">Tags</div>
<div id="itemsmodel"></div>
<br>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
And there is javascript file:
var models = document.getElementById("NumberOfQuestions");
var modelsTable = document.getElementById("itemsmodel");
models.addEventListener("change", drawModels, false);
function drawModels() {
var modelsNum = parseInt(models.value);
var curModels = modelsTable.childElementCount;
if (modelsNum > curModels) {
var delta = modelsNum - curModels;
for (var i = 0; i < delta; i++) {
var input = document.createElement("div");
input.className = "editor-field";
input.innerHTML = "#Html.ListBoxFor(x => x.TagIdList, (MultiSelectList)ViewBag.Tags, new { #class = \"chzn-select\", data_placeholder = \"Tags...\" })";
modelsTable.appendChild(input);
}
} else {
while (modelsTable.childElementCount > modelsNum) {
modelsTable.removeChild(modelsTable.lastChild);
}
}
}
drawModels();
My ViewModel: ExamModel.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ExamGenerator.Models
{
public class ExaminationModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<int> TagIdList { get; set; }
public int NumberOfQuestions { get; set; }
public string Content { get; set; }
}
}
My ActionResult Generate() in controller:
public ActionResult Generate()
{
ViewBag.Tags = new MultiSelectList(genKolEnt.TAGS, "Id", "Name", null);
return View();
}
While you can generate HTML in Javascript using Razor, if the Javascript is in an MVC view, I find that injecting into JS leads to maintenance problems. You ideally want all your JS in separate files to allow for bundling/caching and the ability to break-point the JS code (which is harder in the view).
Either inject only simple things into JS on the page, or inject elements instead.
You can inject your template Razor list into a dummy script block, so you can extract the html from it later. The type="text/template" means the browser will ignore it e.g.:
<script id="ListTemplate" type="text/template">
#Html.ListBoxFor(x => x.TagIdList, (MultiSelectList)ViewBag.Tags, new { #class = "chzn-select", data_placeholder = "Tags..." })
</script>
The view page now looks like this (left out the irrelevant parts):
#section styles{
<link href="#Url.Content("~/Multiple_chosen/chosen.css")" rel="stylesheet" type="text/css" />
}
<h1>#ViewBag.Title</h1>
<h2>#ViewBag.Message</h2>
<script id="ListTemplate" type="text/template">
#Html.ListBoxFor(x => x.TagIdList, (MultiSelectList)ViewBag.Tags, new { #class = "chzn-select", data_placeholder = "Tags..." })
</script>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Generate</legend>
<div class="editor-label">Numbers</div>
<div class="editor-field" id="NumberOfModels">
#Html.EditorFor(model => model.NumberOfQuestions)
</div>
<div class="editor-label">Tags</div>
<div id="itemsmodel"></div>
<br>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Script now looks like this (jQuery version with JS as comments):
// ListOfTags.js file
// This is a shortcut DOM ready handler for $(document).ready(function(){ YOUR CODE HERE })
$(function () {
// Attach an event handler for the "change" event
$('#NumberOfQuestions').change(function () {
var $numberOfQuestions = $(this); // Convert current DOM element (the counter) to a jQuery element
var $modelsTable = $('#itemsmodel'); // document.getElementById("itemsmodel");
var modelsNum = ~~$numberOfQuestions.val(); // parseInt(models.value);
var curModels = $modelsTable.children().length; // modelsTable.childElementCount
var delta = modelsNum - curModels;
// While too few, add more
while (delta > 0) {
var $input = $('<div>').addClass('editor-field'); // document.createElement("div"); .className = "editor-field";
var template = $('#ListTemplate').html(); // Fetch the template from a script block (id="ListTemplate")
$input.html(template); // input.innerHTML =
$modelsTable.append($input); // modelsTable.appendChild(input);
delta--;
}
// While too many, remove the last
while (delta++ < 0) {
$modelsTable.children().last().remove(); // modelsTable.removeChild(modelsTable.lastChild);
}
}).change(); // Trigger an initial change event so it runs immediately
});
Notes/tips:
Place any JS in the page, at the bottom of the view, as it is easier to find. It does not matter where the #section Scripts is as the master page determines where it is injected on the final page.
Always use single quotes (') in Javascript constants by default, so that nested strings can be " which are more often required than 's. Just a good habit to get into. In fact if you had used them your code may have worked as you have added \ escaping to the quotes which will mess up the Razor processing
e.g.:
= '#Html.ListBoxFor(x => x.TagIdList, (MultiSelectList)ViewBag.Tags, new { #class = "chzn-select", data_placeholder = "Tags..." })';
If you add a #RenderSection("styles", required: false) to your master page(s) you can do the same thing for CSS as you do for scripts (ensuring all CSS is loaded in the header (for consistency). Just place them in a #section styles block.
e.g.
<head>
...
#Styles.Render("~/Content/css")
#RenderSection("styles", required: false)
...
</head>
~~ is a handy (and fast) alternative to parseInt to convert values to integers.
Use $ as a prefix for jQuery object variables. This makes it easier to remember when to use jQuery methods vs DOM properties.
Test controller code:
private MultiSelectList TagList()
{
var items = new List<KeyValuePair<int, string>>() {
new KeyValuePair<int, string>(1, "MVC"),
new KeyValuePair<int, string>(2, "jQuery"),
new KeyValuePair<int, string>(3, "JS"),
new KeyValuePair<int, string>(4, "C#"),
new KeyValuePair<int, string>(5, "PHP")
};
MultiSelectList list = new MultiSelectList(items, "key", "value", null);
return list;
}
// Get request starts with one list
public ActionResult Test()
{
ExamModel vm = new ExamModel()
{
NumberOfQuestions = 1,
TagIdList = new List<int>()
};
ViewBag.Tags = TagList();
return View(vm);
}
[HttpPost]
public ActionResult Test(ExamModel model)
{
ViewBag.Tags = TagList();
return View(model);
}
If it's a static JavaScript file and you are not generating it dynamically with razor view engine It won't work because in this case there is no processing performed on a server side. It is the same as accessing static html page/css file/image and etc...
On the other hand if this JavaScript is part of some Razor view, which means that it gets rendered by razor view engine, when you have return View() (or anything like that) in your controller action, than this code should work.
The problem is, java script files are not processed by server, so you won't be able to insert anything in those using ASP.NET MVC. Razor files on the other hand are processed on server so you can insert data into those (either through view bag or model).
One way is:
.cshtml:
<script>
var someVariable = '#model.data';
</script>
then use this variable in your javascript file:
function someFunction(){
var myData = window.someVariable;
}
The other way is to have all javascript in .cshtml file and render it as a partial view.
#Html.Partial("Path/to/javascript/in/razor/view")
edit: seeing your code, this will not help you very much.
If you want to dynamically add/remove dom elements, you will have to do it with javascript: either generate them with "document.createElement()" or load them via ajax if you want some server side processing.
#Html.ListBoxFor
is a server side helper that generates tag and fills it up depending on the parameters. You can do that with javascript as well.
In order to write the HTML code of social icons (Twitter, Linkedin, etc) to a textarea so that the user can use that code elsewhere, I would like to get the HTML code of the view element, but I'm having some issues. To help illustrate this better, here is the code that creates the view:
define(function(require, exports, module) {
var _ = require('underscore');
var GridControlView = require('pb/views/grid-control');
var SocialiconsControlDialog = require('pb/views/socialicons-control-dialog');
var template = require('text!pb/templates/socialicons-grid-control.html');
var SocialiconsGridControlView = GridControlView.extend({
template: _.template(template)
,templateVars: {
partials: {
facebook: require('text!pb/templates/socialicons-grid-control-facebook.html')
,twitter: require('text!pb/templates/socialicons-grid-control-twitter.html')
,googleplus: require('text!pb/templates/socialicons-grid-control-googleplus.html')
,pinterest: require('text!pb/templates/socialicons-grid-control-pinterest.html')
,linkedin: require('text!pb/templates/socialicons-grid-control-linkedin.html')
}
}
,control_dialog: SocialiconsControlDialog
});
return SocialiconsGridControlView;
});
And, for example, the Linkedin template looks like this:
<script src="//platform.linkedin.com/in.js?<%- t.cache_buster %>" type="text/javascript">lang: en_US</script>
<script type="IN/Share" data-counter="<%- t.linkedin_option_countmode %>"></script>
What I would like to retrieve, is the parsed template code as text, something such as:
<script type="text/javascript" src="//platform.linkedin.com/in.js?0.4670609195438331">
<script data-counter="top" type="IN/Share+init">
But using something such as:
control_view.render().$el.innerHTML;, control_view.render().$el.html().text() or control_view.render().$el.html().replace(/<\/?[a-z][a-z0-9]*[^<>]*>/ig, ""); doesn't return text; it returns the full HTML, and produces a Linkedin icon (when I just want the text to be written to a textarea).
Any thoughts?
Update **
I noticed that the code control_view.render().$el is working correctly on other places of the application, and returning HTML code, but for some reason in this view where I'm trying it doesn't. The code seems to break at:
$control = control_view.render().el;
and in the console I get an error which is:
TypeError: t is undefined - underscore-min.js (line 3)
Use the .outerHTML property of the $el.
var html = $('<script type="text/javascript" src="//platform.linkedin.com/in.js?0.4670609195438331">' +
'<script data-counter="top" type="IN/Share+init">');
var text = html[0].outerHTML;
$('textarea').val(text);
jsFiddle
If i have such javascript in my razor veiw:
#{
Grid grid = #Model.GetGridFromModel();
Bool isSomething = #Model.GetSomething();
Bool isSomethingMore = #Model.GetSomehtingMore();
Bool isSomethingElse = #Model.GetSomethingElse()
int caseCount = 0;
}
$(document).ready(function () {
$("#tabs").tabs({
show: function (event, ui) {
switch (ui.index) {
#if (isSomething){
<text>
case #caseCount:
change('#grid.Avalue');
break;
</text>
caseCount++;
}
#if(isSomethingElse){
<text>
case #caseCount:
change('#grid.Bvalue');
break;
</text>
caseCount++;
}
#if (isSomethingElseMore){
<text>
case #caseCount:
change('#grid.Cvalue');
break;
</text>
}
}
}
});
funciton change(id)
{
//doing somehting;
}
So i want to put that javascript in separate file and reference that file to my view, and the problem is how may i pass values from razor to javascript when javascript in separate file?
Javascript are files without being parsed by the compiler, so, you have no chance...
What you can do however is to use a dynamic javascript, for example:
<script src="/CustomScripts/scripts.js"><script>
Have a route that says:
routes.MapRoute(
"CustomScripts", "CustomScripts/{id}",
new { controller = "Scripts", action = "GetFile" }
);
Create your controler and use a simple return View(); like
public ActionResult GetFile(string id)
{
// use id as you please
// pass any Model you want
return View();
}
In that view, just put your javascript with Razor syntax.
Or you can use variables and load them up make the use of RenderSection()
in your _Layout.cshtml file add a section in your <head> before any other javascript
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
#RenderSection("script_variables", false)
<script src="#Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/modernizr-2.0.6-development-only.js")" type="text/javascript"></script>
</head>
and in any View that you want to add such variables, just do:
#Section script_variables {
<script type="text/javascript">
var variableA = '#MyVarA',
variableB = '#MyVarB',
variableC = '#MyVarC';
</script>
}
And all other files that you load the script will have such code...
You might declare some js-variables on your page and then use those variables from the .js-file
You might call a function inside your .js-file and send your data as arguments
(Please consider creating one object and fill with your data instead of creating multiple variables.)