I have a jsp file which is getting data from OSGi configuration in AEM, like below
<c:set var="myParam" value="${myConfig.myParam}" scope="request"/>
Now in my JS file, I am initalising my angular app like below:
var app = angular.module('myapp', []);
app.provider("$provider1", [function () {
// Default configuration
var config = {
key1: 'value'
};
return {
configure: function (params) {
angular.extend(config, params);
},
$get: ['$rootScope', function ($rootScope) {
return {
config: config
};
}]
};
}]);
app.config(['$authProvider', function($authProvider) {
$authProvider.configure({
key1: 'myCustomDataFromJSP'
})
}]);
How can I retrieve this myCustomDataFromJSP from my JSP file? In config phase we can't access scope.
Thanks
I would do it in next way:
Add your variable as a data attribute somewhere on your page, like this:
<div id="config" data-jspvar="${myParam}"> </div>
Now register a constant in your angularjs app
Like this:
app.constant('myCustomDataFromJSP', (function() {
// Define your variable
var myCustomDataFromJSP = ...; //you can use smth like this
//window.document.getElementById('config').dataset.jspvar
return myCustomDataFromJSP;
})());
Now you can inject this constant into your config block.
The above answer is good one, But it is good to have a hidden input there rather than a div in the DOM
<input type='hidden' id="config" data-jspvar="${myParam}"> </input >
app.constant('myCustomDataFromJSP', (function() {
var myCustomDataFromJSP = //get the value here
return myCustomDataFromJSP;
})());
Related
I would like to know how to create forms that uses th:object for each object looped in a th:each. For example, I have the following code.
HTML
<th:block th:each="store: ${stores}">
<form th:object="${store}" th:action="#{/modify-store}">
<input th:field="*{idStorePk}"/>
<input th:field="*{name}"/>
<input th:field="*{phoneNumber}"/>
<button type="submit">Modify</button>
</form>
</th:block>
Controller
#RequestMapping(value = "/stores")
public String getIndex(Model model) {
model.addAttribute("stores", storeService.getAllStores());
return "store";
}
So, I would like to add a form for each object, but it seems that it is not possible and I get the following error.
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'store' available as request attribute
So, I decided to add a #ModelAttribute in my controller, but can't get to return the actual store.
#ModelAttribute("store")
public Store getStore(Store store) {
return store;
}
With this approach all my forms have null values. I also tried to add a #PathVariable, but can't see to bind it using th:object. Is there a solution for this?
So for anyone stuck at a similar problem. I find out a work around that might help you out. First, you can't use th:object, it simply won't cut it. Instead, do the following.
<th:block th:each="store: ${stores}">
<form class="store-form" th:action="#{/modify-store}">
<input th:name="idStorePk" th:value="${store.idStorePk}"/>
<input th:name="name" th:value="${store.name}"/>
<input th:name="phoneNumber" th:value="${store.phoneNumber}"/>
<button class="submit-button" type="submit">Modify</button>
</form>
</th:block>
Then just add something similar to the controller.
#PostMapping(value = "/modify-store")
#ResponseBody
public boolean deleteEntry(#ModelAttribute Store store) throws Exception {
// Your code here...
return true;
}
If you want to send it asynchronously then you will need to add some JS code in order for it to work. It should look something like the code below.
const forms = document.querySelectorAll('.store-form');
forms.forEach(form => {
form.addEventListener('submit', event => {
// Stop the normal form submit triggered by the submit button
event.preventDefault();
const formInputs = form.getElementsByTagName("input");
let formData = new FormData();
for (let input of formInputs) {
formData.append(input.name, input.value);
}
fetch(form.action,
{
method: form.method,
body: formData
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error.message))
.finally(() => console.log("Done"));
});
You're sending stores in your controller in model-attribute and on your second controller where you're submitting your form you're using store that's the reason you're getting this error. So correct the spelling error on any one of your controller. Like this :-
#RequestMapping(value = "/stores")
public String getIndex(Model model) {
model.addAttribute("stores", storeService.getAllStores());
return "store";
}
And Your second controller where you're submitting your form will be like this -
#ModelAttribute("stores")
public Store getStore(Store store) {
return store;
}
Ok so I'm submitting a simple form to my Spring Controller through jQuery. Here is the code:
<form id="addNote" role="form" action="addNote" method="POST">
<div class="form-group error">
<label for="note">Enter your Note </label>
<textarea rows="3" cols="50" name="note" class="form-control"
id="note"></textarea>
</div>
<div class="alert alert-danger" style="display: none">
<strong>Error!</strong> Text length must not exceed 100 characters
</div>
<button type="submit" class="btn btn-default">Save Note</button>
$(document).ready(function(){
$("#addNote").submit(function(e){
e.preventDefault();
var formObj = $(this);
var formURL = "addNote";
var formData = $("#note").val();
$.ajax({
url: formURL,
type: 'POST',
data: formData,
success: function(response){
alert(response);
},
error: function(response){
}
});
});
});
And the Controller method:
#RequestMapping(value="/addNote", method=RequestMethod.POST)
public Vector<String> addNote(Locale locale, Model model, HttpServletRequest httpServletRequest, HttpSession httpSession){
String note = httpServletRequest.getParameter("note");
notes.add(note);
ModelAndView mv = new ModelAndView("notes");
mv.addObject("thenotes", notes);
return notes;
}
I need to return the notes object to the jQuery so that I can display it's data as output. But this is the error I'm getting in the Chrome console:
So apparently there is a problem in the path. I have tried changing var formURL = "addNote"; to var formURL = "assessment/addNote"; in the jQuery but it doesn't work.
But for some reason if I change return value of addNote() function in the Controller to ModelAndViewand return mv then it works but it's not the response in the jQuery I need.
First of all You are using AJAX, so You can't return data using modelAndView.You have to return data as xml/json.
In Your javascript code add the following function:
function getContextPath() {
return window.location.pathname.substring(0, window.location.pathname.indexOf("/",2));
}
reference: How do you get the contextPath from JavaScript, the right way?
Then change You formURL to:
var formURL = getContextPath()+"/addNote";
With the above code requests reaches the controller. Within the controller You have to change Your requestMapping a bit:If You want to return some simple message then You can return it as a string(I am not sure whether it is the best way, but this is how I do it)
#RequestMapping(value = "/addNote", produces=MediaType.APPLICATION_XML_VALUE, method = RequestMethod.GET)
#ResponseBody
public String showNote(){
System.out.println("saving note..");
return "<response>Example</response>";
}
If You want to return a Vector or java object to JQuery, then the best idea is to use jackson-mapper or some similar library, You can find info easily with google.A simpler(not necessarily better solution) would be to define a method that would create the xml String by looping through the vector, sth like:
<notes>
<note>note1</note>
<note>note2</note>
</notes>
and return it as a String from controller, and then process xml within JQuery.
I also learn spring, so if someone knows a better solution, I will be happy to read it ;-)
Regards,
Mikajlo8
EDIT:I Have changed the requestMethod to GET, otherwise You have to deal with CSRF TOKENS.If You want to use POST, is is easy to find on the internet how to deal with csrf tokens.
i want to display tree structure dynamically.i am using angularjs and directives but getting json object only.
popupview.js:
app.directive('treeview', function(TreeService,$http) {
return {
scope: {
griddata:'=',
},
restrict: 'AE',
replace: true,
templateUrl: 'app/partials/treeviewgrid.html',
compile: function(cElem, cAttrs) {
return {
pre:function(scope, iElement, iAttrs) {
},
post:function(scope, iElement, iAttrs) {
scope.roleList = scope.griddata;
controller.js:
(function(){
app.controller('myController', function($scope,$http,TreeService){
$scope.roleList =
[{"roleName":"okm:root","roledId":"okm:root","children":[{"roleName":"my","roledId":"my","children":[{"roleName":"self","roledId":"self","children":[{"roleName":"htmlmenu.html","roledId":"htmlmenu.html","children":[]}]},{"roleName":"100.pdf","roledId":"100.pdf","children":[]},{"roleName":"act.txt","roledId":"act.txt","children":[]}]},{"roleName":"test","roledId":"test","children":[{"roleName":"Administration guide.pdf","roledId":"Administration guide.pdf","children":[]},{"roleName":"Quick Install.pdf","roledId":"Quick Install.pdf","children":[]},{"roleName":"test.docx","roledId":"test.docx","children":[]}]}]}];
});
})();
}
};
}
};
});
tree.html:
<!DOCTYPE html>
<html ng-app="myapp">
<body ng-controller="myController">
<treeview griddata="roleList"></treeview>
</body>
</html>
from the above code the out put is:
[{"roleName":"okm:root","roledId":"okm:root","children":[{"roleName":"my","roledId":"my","children":[{"roleName":"self","roledId":"self","children":[{"roleName":"htmlmenu.html","roledId":"htmlmenu.html","children":[]}]},{"roleName":"100.pdf","roledId":"100.pdf","children":[]},{"roleName":"act.txt","roledId":"act.txt","children":[]}]},{"roleName":"test","roledId":"test","children":[{"roleName":"Administration guide.pdf","roledId":"Administration guide.pdf","children":[]},{"roleName":"Quick Install.pdf","roledId":"Quick Install.pdf","children":[]},{"roleName":"test.docx","roledId":"test.docx","children":[]}]}]}];
but expected out put is:
okm:
root
my
self
htmlmenu.html
100.pdf
act.txt.
so please provide suggestion for how to do this.
Thanks.
I propose to use some of existing components like this
https://github.com/eu81273/angular.treeview
example:
var myApp = angular.module('myApp', ['angularTreeview']);
http://jsfiddle.net/eu81273/8LWUc/
How to perform post action by redirecting to the page using jquery.I tried something like this
$.ajax({
type: "POST",
url: response.data.myUrl,
data: JSON.stringify(response.data.myParam),
dataType: "json"
});
I need to redirect to the url posting data to it.But this isnt working out.Can anyone please help me.
You can serialize form fields into JSON and stringify the result.
/**
* Serialize form fields into JSON
**/
(function($){
$.fn.serializeJSON = function(){
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
}
})(jQuery);
So you'll have one string with all fields, put it into an hidden field and submit the form:
myString= JSON.stringify($('#myForm').serializeJSON());
$("#myForm #myString").val(myString);
$("#myForm").attr("action", YOUR_URL);
$("#myForm").submit();
This is supposed to be the form:
<form id="myForm" method="POST">
<input type="hidden" id="myString" />
</form>
I have two JSP pages that must use the same javascript. The script attaches a function on an anchor. This function will call a database operation through the controller and service layer when user click on the anchors.
Both JSP pages has these anchors. Hence, it will be good if I can reuse this script in both pages. I am planning to create a JSP page that only has this script and include this pages in both jsp pages. Is this a good practice in re-using a javascript ? Are there any other better ways to do this ?
This is a snippet of the script:
$(document).ready(function(){
$('a[name*="like"]').click(function() {
var hrefName = $(this).attr("name");
var href = $(this);
$.ajax({
type: "POST",
url: "likeARecipe",
data: 'recipeId=' + $(this).attr("title") + '&operation=' + $(this).attr("name"),
success: function() {
if(hrefName == 'unlike')
{
$(href).attr("name","like");
$(href).text("like");
}else {
$(href).attr("name","unlike");
$(href).text("unlike");
}
}
});
return false;
});
});
UPDATE
I decided to put the script into a common.js script. I place this script under scripts/common.js.
I used tag to render the URL to this script.
<spring:url value="/resources/scripts/common.js" var="common_js" />
<script src="${common_js}" type="text/javascript"><jsp:text/></script>
I configure spring to read this script by specfying these resources in a context file:
<resources location="/, classpath:/META-INF/web-resources/" mapping="/resources/**"/>
However, spring did not load the script in the JSP Pages. Any suggestion on a way to trouble shot the problem ?
UPDATE
I found a solution to this problem. I have to modify the script. I enclosed the script inside a function():
(function(){
alert("test");
$(document).ready(function(){
$('a[name*="like"]').click(function() {
var hrefName = $(this).attr("name");
var href = $(this);
$.ajax({
type: "POST",
url: "likeARecipe",
data: 'recipeId=' + $(this).attr("title") + '&operation=' + $(this).attr("name"),
success: function() {
if(hrefName == 'unlike')
{
$(href).attr("name","like");
$(href).text("like");
}else {
$(href).attr("name","unlike");
$(href).text("unlike");
}
}
});
return false;
});
});
})(jQuery);
Create an external .js file and reference it from both JSP pages, like this:
<script src="displaydate.js" type="text/javascript"></script>
Take a look here: http://www.javascriptkit.com/javatutors/external.shtml