I'm hoping to loop through an array of Thymeleaf variables to generate JSON-LD (with Schema.org), similar to Google's examples for store departments.
I know you can loop through an array in Thymeleaf in HTML like this:
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
Is there a way to do the same into a JSON-LD format?
I am affraid it is not possible to be achieved on client. You need to prepare JSON on server and send it as a string to client.
So prepare you entity for JSON, like this:
#Getter
#Setter
#JsonInclude(JsonInclude.Include.NON_NULL)
public class FaqAnswerLdJson extends AbstractLdJson implements Serializable {
#JsonProperty("name")
private String name;
#JsonProperty("price")
private String price;
...
}
Then serialize it to JSON on server and put to a model.
On client you can render it like this:
<script type="application/ld+json" th:utext="${json}">
</script>
Related
Is it possible to build a table dynamically using Thymeleaf?
Essentially what i hope to achieve is ability to pass any object and the table would show the number of columns representing number of fields in object.
e.g.
Object 1
first name
last name
DOB
Object 2
number
code
street
city
when passed to this same thymleaf table it would generate different results:
Object 1 Table:
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>DOB</td>
</tr>
Object 2 Table:
<tr>
<td>Number</td>
<td>Code</td>
<td>Street</td>
<td>City</td>
</tr>
Concept and the background
This post will give you an idea of how to fetch the properties of a class and get the values of those properties using org.apache.commons.beanutils.PropertyUtils
https://stackoverflow.com/a/13960004/1251350
Implementation Suggestion
Build a bean with the method to use the above methodology to get a map<String, Object> of properties of a passed object.
#Service("objService")
class ObjectService {
public Map<String, Object> convertToArray(Object object){
// the logic to be taken from
// https://stackoverflow.com/a/13960004/1251350
}
}
Then in the thymeleaf template get the object passed as a fragment argument and iterate the map http://forum.thymeleaf.org/How-to-iterate-HashMap-td3621264.html
<div th:fragment="objDisplay(obj)">
<div th:each="entry : #objService.convertToArray(obj)">
<!-- Thymeleaf template to display Map -->
<!-- http://forum.thymeleaf.org/How-to-iterate-HashMap-td3621264.html -->
</div>
</div>
I didn't put the effort to write the code for you, as I believe you can do it youself on this guidance. Cheers!
suppose i have model class look like
public class Person
{
[Required]
[MaxLength(50,ErrorMessage="Full name should be within 50 character")]
public string full_name { get; set; }
[Range(18,80)]
[Required(ErrorMessage="Please provide age")]
public Int32 Age { get; set; }
}
and i have form based on this model class
#{Html.BeginForm("PostData", "Customodelbinder");
<table>
<tr>
<td>First Name : </td>
<td>#Html.TextBox("first_name")</td>
</tr>
<tr>
<td>Middle Name : </td>
<td>#Html.TextBox("middle_name")</td>
</tr>
<tr>
<td>Surname :</td>
<td> #Html.TextBox("last_name")</td>
</tr>
<tr>
<td>Age:</td>
<td> #Html.TextBox("age") </td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" name="Save" value="Save" />
</td>
</tr>
</table>
}
now i like to know when i will submit the form then PostData will be called and how data will automatically posted to Person model class from client side to server side
public void PostData(Person person)
{
}
i search google and found we need to use ModelBinder is it true ? when one should use ModelBinder ?
http://www.codeproject.com/Tips/806415/Model-Binding-using-IModelBinder-and-DefaultModelB
without using ModelBinder can't we post client side data to action method where action method will have person argument and automatically client side person data will be de-serialize to person class ??
please help me how to do it with & without model binder with some sample code. thanks
i search google and found we need to use ModelBinder is it true ?
Partially, DefaultModelBinder does work well in most case where primitive and even complex types involved. So you don't need to consider writing ModelBinder in most cases. I have 6-8 controller and 150+ action and need not written a single binder.
when one should use ModelBinder ?
When the DefaultModelBinder is failing to bind your request data into the model. e.g. you are getting a request from a device that has typical format, security key, data, etc. DefaultModelBinder works on best case match i.e. it will look into you request params and try to find exact name in model, if a match is find, it will copy value in model.
without using ModelBinder can't we post client side data to action method where action method will have person argument and automatically client side person data will be de-serialize to person class ??
Sure you can, we all do that. Using AJAX post method. Pass the model data into the data property in ajax request. If you name your js model correctly, the data will be bind to controller action parameter perfectly. e.g.
var searchResultModel = { searchId: searchId, isSearchEdited: true };
// Get the result view
$.ajax({
url: '#Url.Action("SearchResult", "Search")',
contentType: 'application/json; charset=utf-8',
type: 'POST',
dataType: 'html',
data: JSON.stringify(searchResultModel)
})
.success(function (searchResult) {
$('#contentLoader').html(searchResult);
});
Learning security these days :)
I need to allow users to enter text in a form and allow them some HTML tags: bold, italic, list etc. and to prevent them to add some dangerous JavaScript code.
So I have used this whitelist implementation to sanitize HTML.
But I am still confused about how to save and display it in the right way.
So here what I did:
Model:
public class Post
{
[AllowHtml]
public string Data { get; set; }
}
Controller:
[HttpPost, ActionName("Create")]
[ValidateAntiForgeryToken]
public ActionResult Create(Post model)
{
// Decode model.Data as it is Encoded after post
string decodedString = HttpUtility.HtmlDecode(model.Data);
// Clean HTML
string sanitizedHtmlText = HtmlUtility.SanitizeHtml(decodedString);
string encoded = HttpUtility.HtmlEncode(sanitizedHtmlText);
View:
#using (Html.BeginForm("Create", "Home", FormMethod.Post)) {
#Html.AntiForgeryToken()
#Html.TextAreaFor(a=>a.Data)
<input type="submit" value="submit" />
}
So when I post a form I see:
<p>Simple <em><strong>whitelist</strong> </em>test:</p>
<ul>
<li>t1</li>
<li>t2</li>
</ul>
<p>Image:</p>
<p><img src="http://metro-portal.hr/img/repository/2010/06/medium/hijena_shutter.jpg" /></p>
Becaouse of <p>< I think that I need to decode it first:
<p>Simple <em><strong>whitelist</strong> </em>test:</p>
<ul>
<li>t1</li>
<li>t2</li>
</ul>
<p>Image:</p>
<p><img src="http://metro-portal.hr/img/repository/2010/06/medium/hijena_shutter.jpg" /></p>
Then I sanitize it against whitelist and I get sanitized HTML:
<p>Simple <em><strong>whitelist</strong> </em>test:</p>
<ul>
<li>t1</li>
<li>t2</li>
</ul>
<p>Image:</p>
<p>
1) Should I save it like this in database?
2) Or I need to Encode this result and then save it to database (encoded bellow)?
<p>Simple <em><strong>whitelist</strong> </em>test:</p>
<ul>
<li>t1</li>
<li>t2</li>
</ul>
<p>Image:</p>
<p>
Here I am confused if I put it on the view like this:
#Model.Data
I get this on the view:
<p>Simple <em><strong>whitelist</strong> </em>test:</p> <ul> <li>t1</li> <li>t2</li> </ul> <p>Image:</p> <p>
or
<p>Simple <em><strong>whitelist</strong> </em>test:</p> <ul> <li>t1</li> <li>t2</li> </ul> <p>Image:</p> <p>
So what to do to display this HTML properly (bold, list etc.)?
The rule of thumb is the following:
Store in your database the RAW HTML without any encodings or sanitizings. A SQL server doesn't care if you store some string containing XSS code.
When displaying this output to your page make sure that it is sanitized.
So:
[HttpPost, ActionName("Create")]
[ValidateAntiForgeryToken]
public ActionResult Create(Post model)
{
// store model.Data directly in your database without any cleaning or sanitizing
}
and then when displaying:
#Html.Raw(HtmlUtility.SanitizeHtml(Model.Data))
Notice how I used the Html.Raw helper here to ensure that you don't get double HTML encoded output. The HtmlUtility.SanitizeHtml function should already take care of sanitizing the value and return a safe string that you could display in your view and it will not be further encoded. If on the other hand you used #HtmlUtility.SanitizeHtml(Model.Data), then the # razor function would HTML encode the result of the SanitizeHtml function which might not be what you are looking for.
To framework 4.5, Using MVC 5, use
#Html.Raw(WebUtility.HtmlDecode(item.ADITIONAL_INFORMAtION))
You can save HTML file in database by datatype VARBINARY(MAX) for htmlcolumn .
Convert a html file in binary file (code project link)
insert data in a column like this sample code :
Declare #HTML Varbinary(MAX) = Set HTML Varbinary code here
Insert into table_name (htmlcoulmn)
Value #HTML
Load data on the database ,when you need load file , you should convert htmlcolumn to Nvarchar(max) by this code :
Select CAST(htmlcolumn as nvarchar(MAX)) As HTMLCODE
FROM Table_Name
If this solution has a problem, thank you for writing me a comment.
I hope you for the best
I'm having issues with my MVC3 vb.net application. When I try to post the changes I've made to the controller, the model is not send to the controller.
I've tried to follow many posts like this one and this one, but I'm not sure of how to implement them in my application since my model did not send IEnumerable types.
At the end I only want that the model returns one value for each batch that is the value that I will save to the database.
When I post the model and try to send to the controller the page sends the following by post:
Client=2&Datacenters=20&BatchesForAssignation[0].CenterID=4&BatchesForAssignation[1].CenterID=20&BatchesForAssignation[1].DatacenterID=14...
But I don't know how to convert this querystring to a BatchesForAssignation object, assign it to the model and send to the controller.
NOTE: The values for Client and Datacenters shown in the querystring are not used in the controller. I need the BatchesForAssignation[n].CenterID part.
Can you please point me to found a solution on this?
This are the objects that I'm using in my MVC application (code compacted):
Batch:
Public class Batch
public property ID as integer
public property CenterID as integer
public property name as string
end class
Centers (This object just store all the list of centers that will be assigned to the Batch. The name is just to show the name in the drop down list):
Public class Center
public property ID as integer
public property name as string
end class
(There's also a Batchlist and a Centerlist objects that acts as collections inherited from CollectionBase that stores all the Batch and Center objects. If you need the class definition please let me know but is pretty strightforward).
The model is as follows
Public class ProcessingModel
public property BatchesForAssignation as BatchList
public property Datacenters as CenterList
End class
The Controller is as follows:
<HttpGet()>
<Authorize()> _
Public Function AssignToDataCenters() As ActionResult
Dim model As New ProcessingModel
Dim BatchHandler As New BatchControl
'This line will get the list of batches without datacenter
model.BatchesForAssignation = BatchHandler.GetBatchesAvailable(ConnectionString)
'This method will get the list of Datacenters available
model.Datacenters=BatchHandler.GetDatacenters(ConnectionString)
return View(model)
End Function
HttpPost (This is actually not working because the model returns an empty model):
<HttpPost()>
<Authorize()> _
Public Function AssignToDataCenters(ByVal Model as ProcessingModel) As ActionResult
Dim BatchHandler As New BatchControl
Dim SaveResult as Boolean=false
'This line will get the list of batches without datacenter
model.BatchesForAssignation = BatchHandler.GetBatchesAvailable(ConnectionString)
'This method save the information returned by the model
SaveResult=BatchHandler.UpdateBatches(model)
ViewBag("Result")=SaveResult
Return View(model)
End Function
The View is as follows (is a Strongly-typed view):
#ModelType MVCAdmin.ProcessingModel
#Code
ViewData("Title") = "Assign Batches To centers"
End Code
#Using Html.BeginForm()
#<table id="tblAvailableBatches">
<thead>
<tr>
<th>Assign batch to:</th>
<th>Name</th>
</tr>
</thead>
<tbody>
#code
For i As Integer = 0 To Model.BatchesForAssignation.Count - 1
Dim a As Integer = i
#<tr>
<td>#Html.DropDownListFor(Function(m) m.BatchesForAssignation(a).CenterID, New SelectList(Model.Datacenters, "ID", "name", model.BatchesForAssignation(i).CenterID), " ")</td>
<td>#Model.BatchesForAssignation(i).name</td>
</tr>
Next
End Code
</tbody>
</table>
<input type="button" value="Apply changes" id="btnApply" />
End Using
Thanks in advance
UPDATE 2012-06-14:
After making some researh I found that I can parse the querystring in the controller using request.Form I can parse the results sent by the view. But the querystring keys are in the form BatchesForAssignation[0].CenterID,BatchesForAssignation[1].CenterID,BatchesForAssignation[2].CenterID and so on...
Is there's a better way to do this "automagically" so that the model parses the querystring and sends the parsed object to the controller?
Again...Thanks in advance
After reviewing this question I've found that the best way to create the model and send it to the controller is creating a CustomModelBinder (from the IModelBinder Interface) and parsing the form's querystring on the BindModel method using the controllerContext.HttpContext.Request.Form property. Something like this:
Public Class ProcessingModelBinder
implements IModelBinder
public Function BindModel(controllerContext As System.Web.Mvc.ControllerContext, bindingContext As System.Web.Mvc.ModelBindingContext) As Object
dim model as ProcessingModel = if(nothing.equals(bindingContext.Model),directcast(bindingContext.Model,directcast(DependencyResolver.Current.GetService(typeof(ProcessingModel))
dim Keys as string()=controllerContext.HttpContext.Request.Form.AllKeys
for each key in Keys
'Fill the model required parameters
Next
return model
End Function
And finally register the new Model Builder in the global.asax file
Sub Application_Start()
AreaRegistration.RegisterAllAreas()
ModelBinders.Binders.Add(typeof(ProcessingModel),New ProcessingModelBinder())
RegisterGlobalFilters(GlobalFilters.Filters)
RegisterRoutes(RouteTable.Routes)
End Sub
I hope that this helps someone
Regards
I am writing my first MVC application, and struggling with how best to pass data from my controllers to my views. I have a very simple XML document structured like this. (Yes, this is Magic: The Gathering data)
<setlist>
<set>
<name>Alara Reborn</name>
<block>Shards of Alara</block>
<cards>145</cards>
<code>ARB</code>
</set>
<set>
<name>Archenemy</name>
<code>ARC</code>
</set>
</setlist>
(note that some of the nodes like "Block" and "Cards" are optional.)
On my first attempt, I was trying this:
' Load the set info
Dim doc As New System.Xml.XmlDocument
doc = LoadXML("setinfo.xml")
Dim listSet = doc.GetElementsByTagName("set")
ViewData("sets") = listSet
Then in my view, I was attempting to access the XmlNodeList like this:
<%
If ViewData("sets").count > 0 Then
For i = 1 To (ViewData("sets").count - 1)
%>
<tr>
<td><%= ViewData("sets")(i).SelectSingleNode("code").InnerText%></td>
<td><%= ViewData("sets")(i).SelectSingleNode("name").InnerText%></td>
<td><%= ViewData("sets")(i).SelectSingleNode("block").InnerText%></td>
</tr>
<%
Next
End If
%>
But I get an Object Block or With Block error when trying to access SelectSingleNode("block") on the second "set" node, since that node doesn't have a "block" node.
I also have a feeling that the way I'm approaching the view is all wrong. Is there a better way to get this simple XML data into the view so I can work with it?
You should consider creating a Set class (this will be the Model class in MVC) that the Controller loads the XML into. Then this Set class can then handle the absence of a 'block' element.
Binding your view directly to the serialised representation of your data is generally a bad idea. Even though this is just a first application it would be good to follow the 'rules' of the MVC pattern from the start, and you'll learn/understand more along the way!
A better way to pass your XML document to the view would be to create a class that represents your xml document, serialize your document into the type and then pass the instance of the class to the view.
One easy way to serialize your document into a class is to use the XmlSerializer.
Domain Class:
<System.Xml.Serialization.XmlRoot("setlist")> _
Public Class SetList
Inherits List(Of SetItem)
End Class
<System.Xml.Serialization.XmlType("set")> _
Public Class SetItem
<System.Xml.Serialization.XmlElement("name")> _
Public Name As String
<System.Xml.Serialization.XmlElement("block")> _
Public Block As String
<System.Xml.Serialization.XmlElement("cards")> _
Public Cards As String
<System.Xml.Serialization.XmlElement("code")> _
Public Code As String
End Class
Controller:
Public Class SetController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Using reader As System.IO.FileStream = System.IO.File.OpenRead("SetInfo.xml")
Dim xmlSerializer As New System.Xml.Serialization.XmlSerializer(GetType(SetList))
Dim setList As SetList = xmlSerializer.Deserialize(reader)
Return View(setList)
End Using
End Function
End Class
View (note this is a strongly typed view):
<%# Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of VB.SetList)" %>
<html>
<head>
<title>Test</title>
</head>
<body>
<div>
<table>
<tr>
<th>Code</th>
<th>Name</th>
<th>Block</th>
</tr>
<%For Each setItem In Model%>
<tr>
<td><%=setItem.Code%></td>
<td><%=setItem.Name%></td>
<td><%=setItem.Block%></td>
</tr>
<%Next%>
</table>
</div>
</body>
</html>