html() does not retrieve the whole content - ajax

I am getting the following response
<div id="weblogs">
<tr>
<td nowrap class="bl">1</td>
</tr>
<tr>
<td nowrap class="bl">2</td>
</tr>
</div>
Now I am trying to attach the rows like the following:
function _ajax(postData)
{
loadUrl = "getweblogs.asp";
$.ajax( {
url : loadUrl, // your ajax file
type : 'post',
data : postData,
success : function( resp ) {
alert($("#weblogs" , resp).html());
$('#weblogs > tbody:last').append($("#weblogs" , resp).html());
}
});
return false;
}
The replace is working fine. My problem is, that the htmls elements from the response are removed. I'm getting only 1 and 2. instead of
<tr>
<td nowrap class="bl">1</td>
</tr>
<tr>
<td nowrap class="bl">2</td>
</tr>
I don't know what am I doing wrong. Could someone give me any clue?
Thank you!
Greetings
Magda

What you're trying to do is not so clear. Is there already an element with id="weblogs" in the page? If so, why does your response have an element with the same id (not a good idea), and if not, why are you trying to append an element's contents to itself like that (also, not a good idea)?
Why not just change the server-side to send the html required, without a wrapping div tag (which makes it invalid html anyway, another bad idea), and then use it as-is?
Another problem is that you're trying to select .html() of something that will always be an empty jquery object: $(selector, string) will never match anything. You'll need to make the string a jquery object if you want to search its substructure: string = $(string).
And I think you're misunderstanding the use of $(selector, $obj). The selector must be in the $obj's sub-structure:
$('#foo', $('<div id="foo"><span/></div>')); // returns empty jquery object
So looking for #weblogs in the substructure of an element with id weblogs will also never find anything.

Your question isn't entirely clear, but I'll try and answer: are you working with Internet Explorer? If so, consider this paragraph from the docs:
For example, Internet Explorer sometimes leaves off the quotes around attribute values if they contain only alphanumeric characters.
API docs: html()

Related

Thymeleaf: Form submit on click of table row

I have a table with orders and order ids. I would like to click on a row to view the order details in another page. My code:
<form id="orderDetalsForm" th:action="#{/restaurant/orderdetails}"
method="POST" th:object="${order}">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th scope="col">Order Id</th>
<th scope="col">Order Details</th>
<th scope="col">Date</th>
<th scope="col">Amount</th>
</tr>
</thead>
<tbody>
<tr id="orderRow" th:each="order : ${orders}"
style="cursor: pointer"
th:onclick="'getOrderItems(\''+${order.orderId}+ '\');'">
<td scope="row" th:text="${order.orderId}"></td>
<td th:text="${order.orderDetais}"></td>
<td th:text="${order.orderDate}"></td>
<td th:text="${order.amount}"></td>
</tr>
<tr>
<td colspan="3">Total</td>
<td th:text="${grandTotal}"></td>
</tr>
</tbody>
</table>
</form>
I tried an ajax form submit:
<script>
function getOrderItems(orderId) {
var url = "/restaurant/orderdetails";
$.ajax({
url : url,
type : "post",
data : {
"orderId" : orderId
},
success : function(data) {
console.log(data);
},
error : function() {
console.log("There was an error");
}
});
}
</script>
In my controller I have this:
#PostMapping(value="/restaurant/orderdetails")
public ModelAndView orderDetails(#RequestParam String orderId){
List<Product> orderDetails = userService.getOrderDetails(orderId);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("orderDetails", orderDetails);
modelAndView.setViewName("restaurant/orderdetails");
return modelAndView;
}
While the ajax works, the page is not getting redirected to my orderdetails page.
You can't use AJAX to redirect to a page. AJAX is for getting data from the server that is then processed/displayed using JavaScript. You however basically want clicking on the row to behave like clicking a link or (since you are using a POST mapping) submitting a form.
First off, using POST makes this a bit more complicated. You should consider using a GET mapping, not only because it makes this problem easier, but also because a POST mapping isn't really appropriate here. POST is used to send data to the server, which you are not doing.
Another thing you should consider it that using a (pure) JavaScript solution to link the table row hinders accessibility. For example, users that can't/don't use a mouse (such as disabled people or search engines) won't be able to see or even use such a link. To solve this it is a good idea to add a proper link to the row. Then that link can used by "clicking" on it with the JavaScript of the click handler.
<tr th:each="order : ${orders}" onclick="orderRowClick(this)">
<td scope="row"><a th:href="#{/restaurant/orderdetails(orderId=${order.orderId})}" th:text="${order.orderId}"></a></td>
<td th:text="${order.orderDetais}"></td>
<td th:text="${order.orderDate}"></td>
<td th:text="${order.amount}"></td>
</tr>
<script>
// Look for a link in the row and click on it
function orderRowClick(row) {
row.querySelector("a").click();
}
</script>
Several more points:
IDs must be unique in HTML. By putting id="orderRow" on such a repeated row will result in invalid HTML.
You shouldn't be using on... attributes to assign event handlers. I'm just using it here or otherwise this answer will go too far.
Remove the <form> from around the table. It doesn't do anything.
If you do want to/have to use a POST mapping, then replace the link in the table row with a form with a hidden field containing the order ID and a submit button and in the JavaScript look for the form instead of the link and submit it: row.querySelector("form").submit();.
BTW there are several (possibly better) ways to do what you are trying. For example:
Forget the JavaScript and just put a link into every cell. With the right CSS the row/cells can be changed so that it looks like you are clicking on the row.
It seems like you are using Bootstrap, which has the "stretched link" feature. Unfortunately it's a bit tricky to get to work with table rows, but it's worth looking at.
What I've understand so far is that you want to redirect user to a new page when the user clicks on the button on the table, for that there're different approaches -
Issue with your approach -
Since you're using ajax it wont be redirecting user to a new page ( because thats exactly how a AJAX works, for more info on AJAX us this link - https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX ), unless you explicitly tells your ajax-code to redirect the user on a new page.
For that you can simply put your page redirection code to a on your ajax success, something like this -
<script>
//your code
$.ajax({
// your code
success : function(data) {
//page redirection code here
window.location.href = "your-base-URL/restaurant/orderdetails/orderId="+orderId;
},
error : function() {
console.log("There was an error");
}
});
}
</script>
PS - This is not efficient programming practice since you're technically making an extra call to your server un-necessarily.
Approach 2nd
Simply make your html table buttin a-href link , like this -
<html>
// your code
<a th:href="#{'/restaurant/orderdetails/orderId=' + ${order.orderId}}">Order details button </a>
//your rest of the code
</html>
Approach-3rd , You can alternatively use java-script function for page redirection as well, simply modify you ajax function , something like this -
function getOrderItems(orderId) {
//page redirection code here
window.location.href = "your-base-URL/restaurant/orderdetails/orderId="+orderId;
}

ngtable filters not working

I am trying to implement ngtable in order to have out of the box filters and pagination but it seems not to be as easy to implement as they say.
My data is loading correctly in the table, however the actual filters are not responding at all. Below is my table code inside the MyCtrl:
<table ng-table="tableParams" class="table table-condensed table-bordered table-striped">
<tr ng-repeat="movie in items.movies">
<td data-title="'Title'" filter="{ title: 'text'}" sortable="'title'">{{movie.title}}</td>
<td data-title="'Duration'" filter="{duration: 'number'}" sortable="'duration'">{{movie.duration | durationFilter | date:'HH:mm:ss'}} hrs</td>
</tr>
</table>
In the app.js I serve data factory to the controller then trigger the ng table:
app.controller('MyCtrl', function($scope, itemsFactory){
itemsFactory.getItems().success(function(data){
$scope.items = data;
tableParams = new NgTableParams({}, { data: data});
});
});
The result is that all the data is displayed and the input filters above the content, however, neither work. Is there something I am missing?
Supposing your HTML contains something like <table ng-table="tableParams", you want to assign your new NgTableParams to $scope.tableParams so the table can see them. Currently you are assigning a local variable.
Also, enable Javascript strict mode by "use strict". Avoids errors like that.
try to change your code
<tr ng-repeat="movie in items.movies">
to
<tr ng-repeat="movie in $data">

get previous td element to manipulate in Ajax call

How would I go about grabbing the previous td element in a table in order to change it's text value inside an Ajax call?
This is what i have so far. I think I am grabbing the td element properly and placing it into the variable, however I cannot get an alert to pop up with the text on the td element I'm trying to alter and I can't actually change the text like I'm trying to do.
function ChangeStatus(id) {
var td = $(this).parent('td').prev();
$.ajax({
type: 'GET',
url: '#Url.Action("changeStatus","AgentTransmission")',
data: { id: id },
dataType: 'json',
success: function (data) {
td.empty();
td.html("Hold");
}
});
}
Edit
Here are the two td elements I'm working with. When the user clicks the Hold link w/the ChangeStatus() onclick event, I want to be able to change the text of the previous element from Waiting to Hold.
<td>
Waiting
</td>
<td>
Details
<span> | </span>
<a href="javascript:void(0)" onclick="ChangeStatus(17)" >Hold</a>
</td>
<td align=center id=17>
</td>
First, parent() only get the first parent, if the caller is deeper in the dom, you won't get it. You should use parents(), but i'd recommend using classes instead of tag names, something like this:
$(this).parents('td.myClass').prev();
You can also use:
console.log(myString);
instead of alerts, you can see the result in the console, using chrome or firebug in firefox
Hope it helps
Try getting the td like this:
var td = $(this).closest('td');

In Selenium using Ruby, how would I select this updated element's text using xpath?

I'd like to select the text inside 'updatedOn_1756', which would typically return something like "10:12 PM". How would I do this? I thought it would be something like element = driver.find_element(:id, "updatedOnID"), but that doesn't work. I'm using Firefox, incidentally.
EDIT: I believe the page is dynamically updated. Though there is no text inside the source shown here, there is a time displayed on the page (it doesn't show in the page source when I click 'view source').
<tr id='row_for_1756' >
<td class="IDClass">1756</td>
<td>Jameson</td>
<td><a id='DrinkName_1756' class="linkToClient" title="Launch Live Viewer" href='/client/Client.application?myid=1756'>Stevens 18</a> -
<a title="BETA Client" href='/client/Client.application?bell=1756' style="color: green; font-weight: bold;">(BETA VERSION)</a> - <a id='DrinkName_Old_1756' class="linkToClient" title="Version before" href='/client/blank/Client.application?myid=1756' style="color: Red;">(old version)</a></td>
<td>9980</td>
<td><span id='updatedOn_1756' class="updatedOnID"></span></td>
<td><span id='histUpdatedOn_1756' class="updatedOnID"></span></td>
</tr>
The reason it doesn't work is because you're asking for an id with the value updatedOnID, which doesn't exist. There is a class with that value, but since you're looking for the id, you'll need the entire ID value, including the number:
driver.find_element(:id, "updatedOn_1756")

Spring Controllers using REST getting 405 errors

----------------UPDATE----------------
I've entirely re-written my question in attempt to clarify what was apparently not well written. I've also included even more code in the hopes that someone can offer some help. My apologies for the confusing stuff provided earlier.
Basically my problem seems to be that I don't entirely understand Spring and REST. So I'm hoping someone can perhaps clarify things for me and perhaps look over my code and inform me of specifically why it doesn't work. Though I have some idea of the cause I don't understand why it is the way it is.
I've got a very basic Spring app. The user is displayed a page that lists (from the DB) a table made up of two columns filled with usernams and a boolean of whether or not they're enabled.
#RequestMapping(value="/admin/modifyUser", method=RequestMethod.GET)
public void showModifyUser() {}
Clicking on a link in the enabled column simply switches their status. The link is created by sending the user to /admin/access and appending the username and access variable. So, an example would be http://localhost:8080/myApp/admin/access?username=test&access=true (or whatever the exact syntax is). That code was:
#RequestMapping(value="/admin/access",method=RequestMethod.GET)
public String submitModifyAccess(#RequestParam("username")String username,
#RequestParam("access")String access) {
....
return "redirect:/admin/modifyUser";
}
That worked fine. It would update the user's access and return to the page with the table and user data. (Maybe not the best way to implement it?) Later on I wanted to populate data in a Dojo grid and therefore needed the data put into JSON format. Hence I read up in my Spring book on REST and such. So, to start out easy, I decided to make the above Handler RESTful. So I changed it to:
#RequestMapping(value="/admin/access/{username}/{access}",method=RequestMethod.GET)
public String submitModifyAccess(#PathVariable String username,
#PathVariable String access) {
....
return "redirect:/admin/modifyUser";
}
I also updated the JSP to make the link go to /admin/access/username/access, so for example: http://localhost:8080/myApp/admin/access/test/true. And voila, things still worked. I assumed I had made it RESTful. A couple of things did strike me as odd though.
First, when clicking on the link, it did update the status properly, but when returning to the /admin/modifyUser page (which is where it sends you), the two variables would be appended to the URL. So instead of showing http://localhost:8080/myApp/admin/modifyUser, it showed http://localhost:8080/myApp/admin/modifyUser?username=test&access=true. Pretty sure that wasn't supposed to be happening.
Second, I realized that the RequestMethod for submitModifyAccess should be POST (or perhaps PUT).
But as I said, it still worked so I didn't worry about it too much.
Next I tried to modify the other link, the username link. When clicking on that link the user is taken to a form populated with the data of that person. Originally that was called by just appending the username to the URL with a GET request to display the form. So the code was:
#RequestMapping(value="/admin/editUser", method=RequestMethod.GET)
public void showEditUser(Model model, #RequestParam("username") String username) {
NFIUser user = userService.getUser(username);
UserDetails userDetails = userDetailsManager.loadUserByUsername(username);
....
model.addAttribute("user", user);
}
Worked fine. So I updated the JSP so the username links called the proper URL and then I tried to RESTify this method by changing it to:
#RequestMapping(value="/admin/editUser/{username}", method=RequestMethod.GET)
public String showEditUser(Model model, #PathVariable String username) {
NFIUser user = userService.getUser(username);
UserDetails userDetails = userDetailsManager.loadUserByUsername(username);
....
model.addAttribute("user", user);
return "redirect:/admin/editUser";
}
Upon doing that I started to see 405 errors and I now realize I'm clearly not understanding something. First, I believe that in order to do a REST PUT or POST you have to have a GET of that exact same URL. Is that correct? What do people think I should do in this situation?
Oh, and in case anyone wants it, the form I was sending people to is as follows (though it's not ever getting loaded as when the user clicks on the link they get the 405 error):
<div align="center">
<b>If you change the Username you MUST change the password as well.</b>
<s:url value="/admin/editUser" var="edit_url" />
<sf:form method="POST" modelAttribute="user" dojoType="dijit.form.Form" action="${edit_url}">
<script type="dojo/method" event="onSubmit">
if (!this.validate()) {
return false;
}
return true;
</script>
<sf:hidden path="username"/>
<table>
<tr>
<td align="right">Username: </td>
<td>
<sf:input path="newUsername" dojoType="dijit.form.ValidationTextBox" trim="true" required="true" value="${user.username}"/>
</td>
</tr>
<tr>
<td align="right">Password: </td>
<td>
<sf:input path="password" type="password" dojoType="dijit.form.ValidationTextBox" required="true"/>
</td>
</tr>
<tr>
<td align="right">Enabled: </td>
<td>
Yes<sf:radiobutton path="enabled" value="true" dojoType="dijit.form.RadioButton"/>
No<sf:radiobutton path="enabled" value="false" dojoType="dijit.form.RadioButton"/>
</td>
</tr>
<tr>
<td align="right">Admin: </td>
<td>
Yes<sf:radiobutton path="isAdmin" value="true" dojoType="dijit.form.RadioButton"/>
No<sf:radiobutton path="isAdmin" value="false" dojoType="dijit.form.RadioButton"/>
</td>
</tr>
<tr>
<td align="right" colspan="2">
<button dojoType="dijit.form.Button" type="submit">Submit</button>
</td>
</tr>
</table>
</sf:form>
</div>
So hopefully that makes things more clear. Again, if you've got some idea of what I'm doing wrong, if you can explain what I clearly don't get about REST, or any other comments that would improve my code, by all means let me know. Thank you very much.
First the main issue, your 405 error. 405 means "method not supported", i.e. the HTTP method (GET/PUT/POST/etc.) is not supported. Your redirect to /admin/editUser will return a 302 to the client (browser) with a header indicating the redirect URL. The browser will then issue a GET against the URL (i.e. it will redirect itself). From your mappings it looks like the closest matching request you can handle is GET /admin/editUser/{username} - but you are redirecting to GET /admin/editUser. My guess is that is the problem - your redirect does not match any endpoints you've declared.
Note I'm assuming your /admin/editUser/username URL in your example should really have been /admin/editUser/{username} because you need to use curly braces for #PathVariable's.
Also note that it is a bit uncommon to redirect from a GET. You just got something, presumably to return to the client - why redirect to something else?
Regarding whether something like http://localhost:8080/myApp/admin/access/test/true is "RESTful" may be an opinion, but my take is that it is not. The resource to me is the user's "access". To grant access I would probably do a PUT /users/{username}/access. To deny access I would probably do a DELETE /users/{username}/access. Note the uniform interface: different HTTP methods operating on the same URL.
If you have verbs in your URLs (e.g. "modifyUser") or pass data in your URLs (e.g. the true in access=true or /access/true) you are probably not adhering to REST principles.
Lastly, I feel you could benefit from a good book on REST rather than what I am guessing you are using is blogs/articles found online. I find Rest in Practice to be the best so far.
modifyUser vs. editUser ?
You wrote that the link is:
http://localhost:8080/myApp/admin/modifyUser
but you mapped to
/admin/editUser/{username}
If this is not the problem, then try to make your question a bit more clear - especially what is the current implementation and what does not work currently.

Resources