Array of object's index from request attribute in jsp and javascript - javascript

Is it possible to:
1
When I do:
$('#NContrato' ).val('${personList[0].NContrato}');
It works. But if I do
$('#NContrato' ).val('${personList[' + ind + '].NContrato}');
$('#NContrato' ).val('${personList[ind].NContrato}');
$('#NContrato' ).val('${personList[${ind}].NContrato}');
It doesn't and this is request.setAttribute(personList, ...) in a controller (I'm using spring MVC)
$('#NContrato' + ind) // JQuery $() ...It works but
${'${personList[' + ind ...} //Request ${} doesn't work concatenating string's
${personList[0].NContrato} // Works
Is there a way to do it?
2
I'd like to change
newPerson to have the clone of
${personList[0]}
I tried this ...
<script type="text/javascript">
function setNewPerson(ind) {
${newPerson=personList[0]};
}
</script>
but .... it gives this error:
org.apache.jasper.JasperException: /WEB-INF/pages/t4imovelZMAguaEdpGass.jsp(153,3) PWC6038:
"${newPerson=personList[0]}" contains invalid expression(s): javax.el.ELException:
Error Parsing: "${newPerson=personList[0]}"
EDIT:
JSP
<c:forEach items="${personList}" var="item" varStatus="status">
.....
<button type="button" onclick="change(${item.id},${status.count})"></button>
.....
</c:forEach>
.....
<form:form action="save()" method="post" modelAttribute="newPerson" id="personId" >
....
<form:input path="NContrato" id="NContrato" />
....
</form>
<script type="text/javascript">
function change(id, ind) {
$('#NContrato' ).val('${personList[0].NContrato}'); //Works
var ind=0;
$('#NContrato' ).val("${'personList[' + ind + '].NContrato'}"); // <- 1 Question
....
${newPerson=personList[0]}; // <- 2 Question
}
</script>
Controller (Servlet)
#RequestMapping(value="/saves*", method = RequestMethod.POST )
public #ResponseBody ModelAndView save(#ModelAttribute("newPerson") Person person,
BindingResult errors, HttpServletRequest request) throws Exception {
...
request.setAttribute("newPerson", subForm);
...
request.setAttribute("personList", personManager.getPersonList())
....
return new ModelAndView( "personJSP");
}

If you start coding JSP using EL without first learning the basics, the original old way of doing things, you will be forever confused. EL's ${} looks kind of like jquery's $() operator, but it is not.
The EL expression
${personList[0].NContrato}
is equivalent to
<%= personList[0].NContrato %>
or
<% out.print( personList[0].NContrato ); %>
It runs on the server side and prints the value of personList[0].NContrato into the HTML source you are building.
The expression
${personList[' + ind + '].NContrato}
does nothing. Why? Because ${} runs on the server and only prints variables. There is no variable named "personList[' + ind + '].NContrato". That exact text "${personList[' + ind + '].NContrato}" will be printed into your HTML source. Hence the importance of viewing the source in the browser when troubleshooting.
As for
${newPerson=personList[0]};
you can't do an assignment like that in EL. Ask yourself if the following would make any sense at all?
<% out.print( newPerson=personList[0] ); %>
It doesn't make sense to do an assignment inside a print command.

Related

Unable to read value from document

I'm a novice in MVC, Below is my code
I am unable to read the value of an ID and use that in an decision statement, I am getting "The name "Text" does not exist in current context", I need to work on the if statement based on the value I get from my document.getElementById
#{
var grid = new WebGrid(Model.Abc, canPage: true, canSort: true, rowsPerPage: 50);
}
#{
var gridColumnsNew = new List<WebGridColumn>();
gridColumnsNew.Add(grid.Column("Details", header: "Id"));
<text>
var obj = document.getElementById("NextAction").value;
</text>
if (#text.obj == "Start")
{
gridColumnsNew.Add(grid.Column("Temp"));
}
}
Try using
document.getElementsByName("NextAction").value;
I have seen in my case that Blazor changes Id to name.
Note: I am using DevexpressBlazor
Did you checked if you are able to see on the html generated that ID?
If yes, Did you have any JS error before?
Looks like the ID not was generated or the place where you are run the getElementById don't have visibility to your specific code.
You are mixing razor syntax and javascript. The line var obj = document.getElementById("NextAction").value; is javascript and should go inside <script> tag. You can't call javascript functions from razor code.
Solution:
Assuming you have a controller named GridController.cs and a view named Grid.cshtml. Inside your controller add a new HttpPost action:
[HttpPost]
public IActionResult NextAction(string nextAction)
{
ViewData["NextAction"] = nextAction;
return View("Grid");
}
Inside the view add a form that posts the nextAction value to the controller:
<form asp-action="NextAction" asp-controller="Grid">
<input type="hidden" value="Start" name="nextAction" />
<button type="submit">Start</button>
</form>
The controller added the NextAction value in the ViewData dictionary so now the view can access it:
#{
var gridColumnsNew = new List<WebGridColumn>();
gridColumnsNew.Add(grid.Column("Details", header: "Id"));
if (ViewData["NextAction"] == "Start")
{
gridColumnsNew.Add(grid.Column("Temp"));
}
}
You are getting that error because you are using #text.obj. In Razor, once you attached # before any identifier, it considers it a C# or VB variable.
Since we don't have your entire page, you may need to clarify where the source of the NextAction. It will be helpful. See a sample of something similar.
#if(item.Ward == "start")
{
gridColumnsNew.Add(grid.Column("Temp"));
}
The item is from the model I am iterating to form the grid.

Javascript: .value is undefined (involves NodeJs also)

So In my node I do an API and send it to my index.ejs page like
app.get("/", function (req, res) {
request("http://something/API", function (error, response, body){
if(!error && response.statusCode == 200) {
var result = JSON.parse(body) //Converts it into object
console.log(result)
res.render("home.ejs", {result:result});
}
})
})
Now In my Index Page, I do something like this
<% for ( var i= 0; i<result.length; i++ ) { %>
<table text-aling="left">
<tr>
<td> <%= i+1 %> </td>
<td> <p class="c"><%=result[i]["long"]%></p> (<%= result[i]["short"] %>) </td>
<td> <%= result[i]["price"] %> </td>
followed by a script just below body and head tag to do DOM manipulation.
<script type="text/javascript">
var x = document.getElementsByClassName("c")[1].value
console.log(x);
</script>
Now, Console.log(x) says undefined (while it does display result from API call on my frontend. Is it because it is an object? or what am I missing here? How can I get the value displayed on my frontend at my console.log
Your <p> does not have a value attribute. Use innerHTML:
x = document.getElementsByClassName("c")[1].innerHTML
I think the issue you are experiencing could be due to one of a few problems:
The placement of the tag
Make sure you place the script tag at the bottom of your html to ensure the above elements have fully rendered before the script is called. If the script runs before the elements with class "crypto" have loaded, the variable 'x' will be empty.
The number of elements with the class "crypto"
While I don't see any elements with class "crypto" in your example, you are trying to set variable 'x' to the element in the array at index 1 (the second position). If you have fewer than two elements with the class "crypto", trying to select index 1 will be undefined. If you're trying to select the first element with the class "crypto", use "var x = document.getElementsByClassName("crypto")[0].value" instead.
The presence of the class "crypto"
I see you list an element with the class "c", though none with the class "crypto". If you are trying to select the element with class "c", , use "var x = document.getElementsByClassName("c")[0].value" instead.

Better approach than hidden field to store data in html

I'd like to know if a better approach exists to store data in html content.
At the moment I got some values stored in my html file using hidden field. These values are generated by code behind.
Html:
<input type="hidden" id="hid1" value="generatedValue1" />
<input type="hidden" id="hid2" value="generatedValue2" />
And therefore I get those values on client side using jquery, in order to pass them to an ajax request.
JQuery
$.ajax({
data:{
var1 : $('#hid1').val(),
var2 : $('#hid2').val()
}
);
So is this the correct way to do this, or does it exist a smoother solution to achieve the same result? Since I don't need these values to be posted on page submit the input hiddenis probably gross.
What I usually do is adding the values as data- attributes to the html form:
<form data-field1="generatedValue1" data-field2="generatedValue2">
...
</form>
And then, retrieve them with jQuery:
...
$form = $( my_selector_to_take_the_form );
data:{
var1 : $('form').attr('data-field1'),
var2 : $('form').attr('data-field1')
}
With this, you won't post any hidden field
If you don't need those in a form, then just make them variables in your JavaScript. To output them, encode them via the JavaScriptSerializer class:
<%
// Presumably somewhere in your C# code...
JavaScriptSerializer serializer = new JavaScriptSerializer();
%>
<script>
var hid1 = <%= serializer.Serialize(valueForHid1) %>;
var hid2 = <%= serializer.Serialize(valueForHid2) %>;
</script>
(See note below about globals.)
Using them later:
$.ajax({
data:{
var1 : hid1,
var2 : hid2
}
);
Globals: As shown there, hid1 and hid2 end up as globals (on most browsers, they do when you use hidden fields as well). I recommend not using globals, but instead wrapping everything in scoping functions:
(function() {
var hid1 = <%= serializer.Serialize(valueForHid1) %>;
var hid2 = <%= serializer.Serialize(valueForHid2) %>;
// ....
$.ajax({
data:{
var1 : hid1,
var2 : hid2
}
);
})();
If for some reason you have to use a global, use just one:
var myOneGlobal = {
hid1: <%= serializer.Serialize(valueForHid1) %>,
hid2: <%= serializer.Serialize(valueForHid2) %>
};
Using that later:
$.ajax({
data:{
var1 : myOneGlobal.hid1,
var2 : myOneGlobal.hid2
}
);
You can output an entire object graph to one variable (perhaps myOneGlobal) with the serializer:
<script>
var myOneGlobal = <%= serializer.Serialize(objectWithData) %>;
</script>
You can use the new HTML5 "data" attributes. (http://html5doctor.com/html5-custom-data-attributes/)
Your codebehind section would do something like this:
<ul data-listname="{put name here}">
<li data-key="{put key here}>
Item1
</li>
</ul>
And then in your jQuery you can do:
var firstId = $('li').first().data('id');
var list = $('ul').data('listname');
Make sure to only use lowercase after the data-
I have found, that it will not work correctly otherwise.
You can also set the data like this:
$('#something').data('smthgnelse', 'Hi there');
You should use the HTML5 data attribute.
i.e My Link
You can easy access this attributes i.e with jQuery
$(".mylink").attr("data-YOURKEY");
John Resig explained it well:
http://ejohn.org/blog/html-5-data-attributes/
Please also read the specs from HTML5-Doctor
http://html5doctor.com/html5-custom-data-attributes/
..and if you like to go a bit deeper:
http://www.w3.org/html/wg/drafts/html/master/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes

Load JSP file into Javascript to realize Fragments

I'm working with SringMVC and I'm searching for an easy solution to load a JSP into a div box of another JSP file. I heard about using Tiles but I would prefer to use ajax/jquery. Can anyone help me with that? I'm trying to get this working for two days now...
My current approach is something like this:
$(document).ready(function() {
var html = '<jsp:include page="searchSites.jsp"/>';
$('#contentbox').load(html);
});
But this is throwing an "Uncaught SyntaxError: Unexpected token ILLEGAL" Error at the second line. I also tried c:import but this isn't working, too.
Thank you very much for your help!
Edit:
#Controller
#RequestMapping("/search")
public class SearchController {
#Autowired private SiteService siteService;
#Autowired private SystemService systemService;
#RequestMapping(value = "")
public String displaySearch(Model model) {
return "displaySearch";
}
#RequestMapping(value = "sites", method = RequestMethod.POST )
public String displaySites(Model model, #RequestParam String searchStr) {
List<RSCustomerSiteViewDTO> sites = siteService.getSitesByName(searchStr);
model.addAttribute("sites", sites);
return "searchSites";
}
#RequestMapping(value = "systems", method = RequestMethod.POST)
public String displaySystems(Model model, #RequestParam String searchStr) {
List<RSServicedSystemViewDTO> systems = systemService.getSystemsByName(searchStr);
model.addAttribute("systems", systems);
return "searchSystems";
}
}
displaySearch.jsp
<html>
<head>
<title>Site</title>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<link rel="stylesheet" href="<c:url value="resources/css/style.css" />" />
<script>
$(document).ready(function() {
var html = '/crsp/search/sites';
$('#contentbox').load(html);
});
</script>
</head>
<body>
<div id="content">
<div id="searchdiv">
<form method="POST" action="search/sites">
<input type=text name=searchStr placeholder="Search Site..."
id="searchSite" class="search" />
</form>
<form method="POST" action="search/systems">
<input type=text name=searchStr placeholder="Search System..."
id="searchSystem" class="search" />
</form>
</div>
<div id="contentbox">
</div>
</div>
</body>
</html>
searchSites.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# page session="false"%>
<table>
<tr id="header">
<td>Name</td>
<td>Customer</td>
<td>City</td>
<td>Region</td>
</tr>
<c:forEach var="site" items='${sites}' varStatus="loopStatus">
<tr class="${loopStatus.index % 2 == 0 ? 'even' : 'odd'}">
<td>${site.siteName}</td>
<td>${site.customerName}</td>
<td>${site.siteCity}</td>
<td>${site.regionName}</td>
</tr>
</c:forEach>
</table>
Edit:
I came closer. I have to fire something like this from the forms instead of the action which I got until now, then it will work: Suggestions?
function searchSites(searchStr) {
$.ajax({
type: "POST",
url: "sites?searchStr=",
success: function(data) {
$("#contentbox").html(data);
}
});
}
You should remove the JSP tag
var html = 'searchSites.jsp';
$('#contentbox').load(html);
The load method should be provided with a url that corresponds with a mapping to one of your controller methods.
Controller
#Controller
#RequestMapping("/site")
public class MyController{
#RequestMapping("/search")
public String getFragment(){
return "fragment";
}
}
Javascript
$(document).ready(function() {
var html = "/contextRoot/site/search"; //you may need to use jstl c:url for this
$('#contentbox').load(html);
});
Config
Please note this example, assumes you have a ViewResolver setup in your dispatcher configuration file as follows and there is a fragment.jsp file within the root of your WEB-INF directory:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
The basic concept of request handling in Spring MVC is that a request is "somehow" mapped to a controller method. Spring MVC provides various ways of doing this url, request type, parameter presence, parameter values, etc... But basically it boils down to which controller/method should handle this request. This is most often accomplished using #RequestMapping.
After the method is found data binding occurs, meaning that request parameters are supplied to the method as arguments. Once again there are various ways to match parameters to arguments, including path variables, modelattributes, etc...
Next the body of the method is executed, this is pretty much custom and you provide the implementation.
The next part is where you seem to be getting stuck. The controller method next tells Spring what view should be displayed. Once again there are many ways to do this, but one of the most common is to return a String at the end of your method that corresponds with a view (.jsp). Usually a view resolver is registered to avoid hardcoding the name of a view file in the returned String. The returned String is resolved by the ViewResolver and associated view is returned.
To answer your follow up question if you want to serve the displaySearch.jsp after processing a request for search/systems you simply return that viewName.
#RequestMapping(value = "systems", method = RequestMethod.POST)
public String displaySystems(Model model, #RequestParam String searchStr) {
List<RSServicedSystemViewDTO> systems = systemService.getSystemsByName(searchStr);
model.addAttribute("systems", systems);
return "displaySearch";
}

How to use underscore.js as a template engine?

I'm trying to learn about new usages of javascript as a serverside language and as a functional language. Few days ago I heard about node.js and express framework. Then I saw about underscore.js as a set of utility functions. I saw this question on stackoverflow
. It says we can use underscore.js as a template engine. anybody know good tutorials about how to use underscore.js for templating, especially for biginners who have less experience with advanced javascript. Thanks
Everything you need to know about underscore template is here. Only 3 things to keep in mind:
<% %> - to execute some code
<%= %> - to print some value in template
<%- %> - to print some values HTML escaped
That's all about it.
Simple example:
var tpl = _.template("<h1>Some text: <%= foo %></h1>");
then tpl({foo: "blahblah"}) would be rendered to the string <h1>Some text: blahblah</h1>
<!-- Install jQuery and underscore -->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<!-- Create your template -->
<script type="foo/bar" id='usageList'>
<table cellspacing='0' cellpadding='0' border='1' >
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<%
// repeat items
_.each(items,function(item,key,list){
// create variables
var f = item.name.split("").shift().toLowerCase();
%>
<tr>
<!-- use variables -->
<td><%= key %></td>
<td class="<%= f %>">
<!-- use %- to inject un-sanitized user input (see 'Demo of XSS hack') -->
<h3><%- item.name %></h3>
<p><%- item.interests %></p>
</td>
</tr>
<%
});
%>
</tbody>
</table>
</script>
<!-- Create your target -->
<div id="target"></div>
<!-- Write some code to fetch the data and apply template -->
<script type="text/javascript">
var items = [
{name:"Alexander", interests:"creating large empires"},
{name:"Edward", interests:"ha.ckers.org <\nBGSOUND SRC=\"javascript:alert('XSS');\">"},
{name:"..."},
{name:"Yolando", interests:"working out"},
{name:"Zachary", interests:"picking flowers for Angela"}
];
var template = $("#usageList").html();
$("#target").html(_.template(template,{items:items}));
</script>
JsFiddle Thanks #PHearst!
JsFiddle (latest)
JsFiddle List grouped by first letter (complex example w/ images, function calls, sub-templates) fork it! have a blast...
JsFiddle Demo of XSS hack noted by #tarun_telang below
JsFiddle One non-standard method to do sub-templates
In it's simplest form you would use it like:
var html = _.template('<li><%= name %></li>', { name: 'John Smith' });
//html is now '<li>John Smith</li>'
If you're going to be using a template a few times you'll want to compile it so it's faster:
var template = _.template('<li><%= name %></li>');
var html = [];
for (var key in names) {
html += template({ name: names[i] });
}
console.log(html.join('')); //Outputs a string of <li> items
I personally prefer the Mustache style syntax. You can adjust the template token markers to use double curly braces:
_.templateSettings.interpolate = /\{\{(.+?)\}\}/g;
var template = _.template('<li>{{ name }}</li>');
The documentation for templating is partial, I watched the source.
The _.template function has 3 arguments:
String text : the template string
Object data : the evaluation data
Object settings : local settings, the _.templateSettings is the global settings object
If no data (or null) given, than a render function will be returned. It has 1 argument:
Object data : same as the data above
There are 3 regex patterns and 1 static parameter in the settings:
RegExp evaluate : "<%code%>" in template string
RegExp interpolate : "<%=code%>" in template string
RegExp escape : "<%-code%>"
String variable : optional, the name of the data parameter in the template string
The code in an evaluate section will be simply evaluated. You can add string from this section with the __p+="mystring" command to the evaluated template, but this is not recommended (not part of the templating interface), use the interpolate section instead of that. This type of section is for adding blocks like if or for to the template.
The result of the code in the interpolate section will added to the evaluated template. If null given back, then empty string will added.
The escape section escapes html with _.escape on the return value of the given code. So its similar than an _.escape(code) in an interpolate section, but it escapes with \ the whitespace characters like \n before it passes the code to the _.escape. I don't know why is that important, it's in the code, but it works well with the interpolate and _.escape - which doesn't escape the white-space characters - too.
By default the data parameter is passed by a with(data){...} statement, but this kind of evaluating is much slower than the evaluating with named variable. So naming the data with the variable parameter is something good...
For example:
var html = _.template(
"<pre>The \"<% __p+=_.escape(o.text) %>\" is the same<br />" +
"as the \"<%= _.escape(o.text) %>\" and the same<br />" +
"as the \"<%- o.text %>\"</pre>",
{
text: "<b>some text</b> and \n it's a line break"
},
{
variable: "o"
}
);
$("body").html(html);
results
The "<b>some text</b> and
it's a line break" is the same
as the "<b>some text</b> and
it's a line break" and the same
as the "<b>some text</b> and
it's a line break"
You can find here more examples how to use the template and override the default settings:
http://underscorejs.org/#template
By template loading you have many options, but at the end you always have to convert the template into string. You can give it as normal string like the example above, or you can load it from a script tag, and use the .html() function of jquery, or you can load it from a separate file with the tpl plugin of require.js.
Another option to build the dom tree with laconic instead of templating.
I am giving a very simple example
1)
var data = {site:"mysite",name:"john",age:25};
var template = "Welcome you are at <%=site %>.This has been created by <%=name %> whose age is <%=age%>";
var parsedTemplate = _.template(template,data);
console.log(parsedTemplate);
The result would be
Welcome you are at mysite.This has been created by john whose age is 25.
2) This is a template
<script type="text/template" id="template_1">
<% _.each(items,function(item,key,arr) { %>
<li>
<span><%= key %></span>
<span><%= item.name %></span>
<span><%= item.type %></span>
</li>
<% }); %>
</script>
This is html
<div>
<ul id="list_2"></ul>
</div>
This is the javascript code which contains json object and putting template into html
var items = [
{
name:"name1",
type:"type1"
},
{
name:"name1",
type:"type1"
},
{
name:"name1",
type:"type1"
},
{
name:"name1",
type:"type1"
},
{
name:"name1",
type:"type1"
}
];
$(document).ready(function(){
var template = $("#template_1").html();
$("#list_2").html(_.template(template,{items:items}));
});
with express it's so easy. all what you need is to use the consolidate module on node so you need to install it :
npm install consolidate --save
then you should change the default engine to html template by this:
app.set('view engine', 'html');
register the underscore template engine for the html extension:
app.engine('html', require('consolidate').underscore);
it's done !
Now for load for example an template called 'index.html':
res.render('index', { title : 'my first page'});
maybe you will need to install the underscore module.
npm install underscore --save
I hope this helped you!
I wanted to share one more important finding.
use of <%= variable => would result in cross-site scripting vulnerability. So its more safe to use <%- variable -> instead.
We had to replace <%= with <%- to prevent cross-site scripting attacks. Not sure, whether this will it have any impact on the performance
Lodash is also the same
First write a script as follows:
<script type="text/template" id="genTable">
<table cellspacing='0' cellpadding='0' border='1'>
<tr>
<% for(var prop in users[0]){%>
<th><%= prop %> </th>
<% }%>
</tr>
<%_.forEach(users, function(user) { %>
<tr>
<% for(var prop in user){%>
<td><%= user[prop] %> </td>
<% }%>
</tr>
<%})%>
</table>
Now write some simple JS as follows:
var arrOfObjects = [];
for (var s = 0; s < 10; s++) {
var simpleObject = {};
simpleObject.Name = "Name_" + s;
simpleObject.Address = "Address_" + s;
arrOfObjects[s] = simpleObject;
}
var theObject = { 'users': arrOfObjects }
var compiled = _.template($("#genTable").text());
var sigma = compiled({ 'users': myArr });
$(sigma).appendTo("#popup");
Where popoup is a div where you want to generate the table

Categories