Get access to Spring Model variable from JavaScript - javascript

How I can get access to variable (which was added as attribute to Model in my controller) in JavaScript and how I can work with properties of it?
My model:
public class Category {
private Long id;
private String name;
private List<Recipe> recipes = new ArrayList<>();
}
My controller:
#RequestMapping(path = "/", method = RequestMethod.GET)
public String showAllCategories(Model model) {
List <Category> categories = categoryService.findAll();
model.addAttribute("categories", categories);
return "index";
}
On my web page I need to show all categories (no problem, using Thymeleaf th:each="category : ${categories}") and have ability add new category to categories variable and set its properties (id, name, recipes for example).
So, how I can get access to variable 'categories' in JavaScript, and how I can add new element and set properties in JavaScript?

You can make an ajax call to this method
// using jquery
$.ajax({
url:'/',
success:function(response){
// get the return pf the method here
// can be assigned to any variable
}
java method change
#RequestMapping(path = "/", method = RequestMethod.GET)
public String showAllCategories(Model model) {
//rest of code
return (the value which which you want to assign to model property);
}
Explore more about ajax

You have to create an API. Rest for example.
The idea is to create methods callable by javascript(via AJAX for example), and do the operations you need to do in java.
Here you have some pseudocode:
#RequestMapping(path = "/addCategory", method = RequestMethod.GET)
public boolean AddCategory(Model model) {
//Do your logic to add category
if (/*everything went good*/) return true;
else return fale;
}

Why you want to use Model?, when you can directly access the object as JSON:
JS Snippet using Angular:
$http.get('/app/get').then(function(response) {
$scope.categoryList = response.data;
}, function(response) {
});
JS Snippet using Jquery:
$.ajax({
url: "/app/get",
type: 'GET',
success: function(response) {
var categoryList = response.data;
console.log(categoryList);
}
});
Java Snippet:
#RestController
#RequestMapping
public class Controller {
#RequestMapping(path = "/get", method = RequestMethod.GET)
public List <Category> showAllCategories() {
return categoryService.findAll();
}
}

Related

passing an array from ajax call to controller, array empty in controller

Can anyone suggest what I need to change here?
I'm getting classes from elements that contain the class 'changed', the classes I get contain id's that I want to pass to the controller method.
When I look in the network tab I can see the data I want in the payload, it looks like this:
{"list":["GroupId-1","SubGroupId-2","changed"]}
but when I put a breakpoint on the controller the list is null.
This is the class I'm expecting in the controller method:
public class MemberGroups
{
public string GroupId { get; set; }
public string SubGrouId { get; set; }
public string Status { get; set; }
}
javascript for the save
function Savechanges() {
var spans = document.getElementsByClassName("changed");
var list = [];
$.each(spans,
function (key, value) {
$.each(value.classList,
function (key, value) {
list.push(value);
});
});
var dataToPost = JSON.stringify({ list: list });
$.ajax({
url: "/umbraco/Api/OrganisationMemberGroupsDashboardApi/UpdateMemberToGroup",
data: JSON.stringify({ list }),
type: "POST",
contentType: "application/json; charset=utf-8", // specify the content type
})
.done(function (data) {
});
}
controller
public string UpdateMemberToGroup( List<MemberGroups> list)
{
// save records
}
The spans are created dynamically and added to a treeview. When they are dragged and dropped all classes are removed then the 'changed' class is added along with the id classes so I only pass the ones I need to to the controller
var s = document.createElement('span');
s.classList.add('node-facility');
s.classList.add('ui-droppable');
s.classList.add('GroupId-' + value.GroupId);
s.classList.add('SubGroupId-0');
s.id=('GroupId-' + value.GroupId);
s.appendChild(document.createTextNode(value.GroupName));
This variant was tested using postman body json -
["GroupId-1","SubGroupId-2","changed"]
Change your ajax data to this:
data: list,
and your controller action:
public string UpdateMemberToGroup([FromBody] []string list)
{
var memberGroups = new MemberGroups
{
GroupId =list[0],
SubGrouId =list[1],
Status =list[2]
};
// save records
}
This variant was tested in postman using
{"GroupId":"GroupId-1","SubGroupId": "SubGroupId-2", "Status":"changed"}
you can put the code in javascript:
var data={GroupId:list[0],SubGroupId:list[1], Status:list[2]}
......
....
data:data,
.....
your controler action in this case:
public string UpdateMemberToGroup([FromBody] MemberGroups memberGroups)
{
// save records
}
And I don't know what version MVC you use , but for some versions instead of [FromBody] better to use [FromForm] or don't use anything at all.

MVC - Send HtmlHelper object by controller Content (function) argument?

Is there a way to return HtmlHelper object from controller to view?
In code:
Controller:
public ActionResult SomeFunc(int id)
{
if (condition)
return Content();//here i would like to send Html.ActionLink("Text", "Action")
else
return Content();
}
The link will get handle in javascript:
$.get("", { id: $("#id").val() }).
done(function (data) {
if (data != 0) {
$("#someDOMID").val(data);
}
});
If you want the content to contain a raw html string then you can create a function to render a partial to a string serverside and return that.
You could then take it another step and create a generic ActionLinkPartial that contained one embedded #Html.ActionLink and accepted a model that had your action link configuration settings.
Something like...
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
And use a model like...
public class ActionLinkModel
{
public string Text{get;set}
public string Action{get;set;}
}
Invoke it like...
var html = this.RenderPartialViewToString("Partials/Html/ActionLinkPartial", model);
If you only need to send a link as mentioned in your question then try this:
public ActionResult GetLink()
{
string url = Url.Action("Index", "Home", new { id = 1 });
return Content(url);
}
Otherwise, it's better to use the Partial View approach.

JAX-RS get body parameters

In javascript I am making an ajax post request to one of my JAX-RS functions like this
var postPackingListRequest = $http({
method: "post",
url: "/rest/v1/submit",
data: $scope.items
});
And now in my JAX-RS method I am trying to get the varibale $scope.items that was passed. I know I can get path params in the path like this
public Response getPathParams(#QueryParam("id") int id) {
But how can I get the data, which is passed in the body?
Thanks
EDIT
#POST
#Path("submit")
#Consumes(MediaType.APPLICATION_JSON)
#ApiResponses({ #ApiResponse(code = 201, response = Response.class) })
#Produces("application/json")
public Response submitPackingList(TestUser testUser) {
}
public class TestUser {
public String id;
public String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
When I send a request to this with the TestUser there I am getting a HTTP 400 error. Here is how I am sending it
var postPackingListRequest = $http({
method: "post",
url: "/rest/v1/submit",
data: "{'user':'1', 'name':james}"
});
Lets say your method is supposed to handle GET request like below
#GET
public Response getPathParams(#QueryParam("id") int id)
Now in the above method every argument must be annotated with something. In your case it is QueryParam. It may be PathParam and several others as well.
Only one argument is allowed which is not annoatated in JAX-RS.
Let's say you have User object like below:
public class User{
String userName;
int userId;
//getters and setters
}
and you want to accept user details that are coming via body of request then your method signature would look like below:
#GET
public Response getPathParams(#QueryParam("id") int id, User user)
Depending upon what the above method consumes whether it be json or xml the request body will be converted to User object and will get bind to your argument.
In case you are using Json you will need explicit MessageBodyReader for it.

ASP.NET MVC - How to "reverse" model binding to convert a C# model back to a query string representation

I have a custom javascript on the client side that I use to build up a querystring and pass over to my asp.net-mvc controller
var templateQueryString = BuildTemplate();
$.ajax({
url: '/MyController/Save?' + templateQueryString,
type: 'post',
dataType: 'json',
success: function (data) {
}
}
and on my controller all of the properties leverage the model binding so it comes in as a single object on the server side. NOTE: that this is a pretty complex object with arrays and arrays of sub objects:
public ActionResult Save(MyTemplate template)
{
}
the issue now is that I need to be able to convert from my C# object back to a string that represents "myTemplateQueryString" on the client side.
Is there any recommended way to take an object and do the "reverse" model binding. They key here is that it generates a string that I could use as a query string again in the future to pass into another asp.ent-mvc controller action.
Here is an example of the querystring that I am storing locally:
<input type="hidden" value="showIds=false&showRisks=false&
amp;statusIds=2&statusIds=1&statusIds=6&statusIds=8&
amp;statusIds=3&statusIds=9&showCompleted=0"
name="filterQueryString" id="filterQueryString">
As #haim770 said it would be easier if you used JSON in the request payload, and not the query string to pass your complex object to the server.
Regarding creating the query string from a model there is not a built-in method that does something like that or any recommended approach as far as i know. An obvious solution is to use reflection and build the query string from your properties.
Assuming your BuildTemplate class looks something like:
public class BuildTemplate
{
public bool ShowIds { get; set; }
public bool ShowRisks { get; set; }
public bool ShowCompleted { get; set; }
public int[] StatusIds { get; set; }
}
You can develop an extension method to convert any object to a QueryString. Here is some initial code you can start with:
public static class ObjectExtensions
{
public static string ToQueryString(this Object obj)
{
var keyPairs = obj.GetType().GetProperties().Select(p =>
new KeyValuePair<string, object>(p.Name.ToLower(), p.GetValue(obj, null)));
var arr = new List<string>();
foreach (var item in keyPairs)
{
if (item.Value is IEnumerable && !(item.Value is String))
{
foreach (var arrayItem in (item.Value as IEnumerable))
{
arr.Add(String.Format("{0}={1}", item.Key, arrayItem.ToString().ToLower()));
}
}
else
arr.Add(String.Format("{0}={1}", item.Key, item.Value.ToString().ToLower()));
}
return "?" + String.Join("&", arr);
}
}
Then you can easily invoke this code on any object to generate a query string:
var person = new BuildTemplate() { StatusIds = new []{ 1, 5, 8, 9 }, ShowRisks = true };
var queryString = person.ToQueryString();
This would generate a query string like:
"?showids=false&showrisks=true&showcompleted=false&statusids=1&statusids=5&statusids=8&statusids=9"
This query string should work just fine with the default model binder for the BuildTemplate class.

How to populate javascript variable with JSON from ViewBag?

I have this Index action:
public ActionResult Index()
{
var repo = (YammerClient) TempData["Repo"];
var msgCol = repo.GetMessages();
ViewBag.User = repo.GetUserInfo();
return View(msgCol.messages);
}
GetMessages returns a list of POCO messages and GetUserInfo returns a POCO with the info of the user (id, name, etc).
I want to fill a javascript variable with the JSON representation of the user info.
So I would want to do something like this in the view:
...
<script>
var userInfo = "#ViewBag.User.ToJson()"
</script>
...
I know that doesn't work, but is there a way to do that? I want to avoid having to do an ajax request once the page is loaded just to get the user info.
In View you can do something like this
#{
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
var userInfoJson = jss.Serialize(ViewBag.User);
}
in javascript you can use it as
<script>
//use Json.parse to convert string to Json
var userInfo = JSON.parse('#Html.Raw(userInfoJson)');
</script>
Was using this solution for simple objects. But I had some problems getting an array to js objects so I'll just leave what I did here.
C#
#{
using Newtonsoft.Json;
ViewBag.AvailableToday = JsonConvert.SerializeObject(list);
}
js
var availableToday = JSON.parse('#Html.Raw(ViewBag.AvailableToday)');
Client-Side Code:
This is an ajax call to a .Net MVC Controller:
var clientStuff;
$.ajax({
type: 'GET',
url: '#Url.Action("GetStuff", "ControllerName")',
data: {},
dataType: "json",
cache: false,
async: false,
success: function (data) {
clientStuff = data;
},
error: function(errorMsg) {
alert(errorMsg);
}
});
Server-Side Code:
CONTROLLER:
public JsonResult GetStuff()
{
return Json(_manager.GetStuff(), JsonRequestBehavior.AllowGet);
}
MANAGER:
public IEnumerable<StuffViewModel> GetStuff()
{
return _unitofWork.GetStuff();
}
UNIT OF WORK:
public IEnumerable<StuffViewModel> GetStuff()
{
var ds = context.Database.SqlQuery<StuffViewModel>("[dbo].[GetStuff]");
return ds;
}
Unit of Work can be a query to a sproc (as I have done), a repository context, linq, etc.
I'm just calling a sproc here for simplicity, although it could be argued that the simplicity lies with Entity Framework and Linq.
You can change this line :
ViewBag.User = repo.GetUserInfo();
To
ViewBag.User = new HtmlString(repo.GetUserInfo());
You should add using Microsoft.AspNetCore.Html; or using System.Web; if HtmlString is not accessible.

Categories

Resources