Angular method understanding - javascript

example code below:
<div id=A>
<div id=B>
<input type="text" onkeyup="some.doSomething()">
</div>
<div id=C>
<button id=btn onclick=some.next('A')>NEXT</button>
</div>
</div>
public doSomething(): void {
//do something
}
public next(): void {
//go next
}
I don't understand the relation between some.next('A') and next() method.
The next method itself isn't taking any parameter, yet div id is included inside html call.

For that Javascript code, you should call in your HTML the method doSomething() directly, the same for next() without params, otherwise won't work.

Related

Prevent javascript firing on load page

I have MVC application with JavaScript in the body of the cshtml page. In Model, I have a method that returns a string, and I want that string to add in some div on a page on click of a button. It works, but, the method is triggered every time I load the page (and I want it to be triggered only on click.
Here is code:
Model:
public class TestJS
{
public string Tekst1 { get; set; }
public string Tekst2 { get; set; }
public TestJS()
{
Tekst1 = "one";
Tekst2 = "two";
}
public string AddTekst()
{
return "three (additional text from method)";
}
}
Controller:
public class TestJSController : Controller
{
// GET: TestJS
public ActionResult Index()
{
Models.TestJS tjs = new Models.TestJS();
return View(tjs);
}
}
View:
#model TestJavaScript.Models.TestJS
#{
ViewBag.Title = "Index";
}
<script type="text/javascript">
function faddtekst() {
whr = document.getElementById("div3");
var t = '#Model.AddTekst()';
whr.innerHTML += t;
}
</script>
<h2>Testing JavaScript Firing</h2>
<p>
First to fields:
#Model.Tekst1;
<br />
#Model.Tekst2;
</p>
<form>
<input type="button" value="Click to show Tekst3" onclick="faddtekst()" />
</form>
<br />
<hr />
<div id="div3">
</div>
I tried to wrap JS in $(document).ready() with same result.
Somebody may think of this as a strange approach, but, a model method that I'm trying to execute takes over 10 seconds in real code, so, I want to prevent waiting every time page loads (waiting should be only if the user clicks button).
The strangest thing is that Model.AddTekst() is executed EVEN if I comment it in javascript function with '//'.
Anyone knows how to avoid unwanted execution of Model.Method?
The behavior you are experiencing is not strange at all. #Model.AddText() executes on the backend once the view is compiled which is normal behaviour.
A comment in razor would look like this
#* Comment goes here *#
But this is not what you want to achieve.
I'm afraid your approach wont work since you can't execute a method on a model asynchronously.
I suggest you take a look at Ajax.BeginForm - more info here
You could implement a controller action on the backend which would return the text you want to display on the submitting of the form.
Try to use e.preventDefault() for button click.
<form>
<input type="button" value="Click to show Tekst3" id="Show" />
</form>
Try with jQuery
$(document).on("click", "#Show", function (e) {
e.preventDefault();
faddtekst();
});

routerlink = "functionName()" invoked immediately upon page load

My component's html is this:
<div id="summary">
<div *ngFor="let question of thisSurvey">
<div>
<span class="badge">#{{question.questionNumber}}</span>
<span>{{question.questionText}}</span>
</div>
<p>Your answer: {{question.questionAnswer}}</p>
</div>
</div>
<br/>
<button class="btn btn-danger yes-no-btn" routerLink="/survey">Go Back</button>
<button class="btn btn-primary" [routerLink]="submitSurvey()" routerLinkActive="active">Finish</button> <!-- Issue here -->
When the page loads, submitSurvey is invoked immediately, and is then constantly invoked. This is submitSurvey:
// Send the answers back to the api for processing
submitSurvey() {
// Make sure everything is answered
const allOKClientSide: boolean = this.surveyService.checkEntireForm(this.thisSurvey);
if (allOKClientSide) {
if (this.surveyService.checkFormOnline(this.thisSurvey).subscribe()) {
return '/placeOne';
}
}
return '/placeTwo';
}
The method begins to hit the service immediately and continues until I kill the server. How do I keep the function from being invoked until the button is clicked? I'm new to Angular and am probably just making a rookie mistake, if so you may point that out as well. Thanks in advance.
[routerLink] is an Input, note the []. So Angular will resolve that immediately and every change detection cycle, to satisfy the template. You want to use (click) which is an Output, note the () and will only call when the button is clicked. Then instead of returning the url on the submitSurvey() function call router.navigate() (inject the router first.)
html
<button class="btn btn-primary" (click)="submitSurvey()" routerLinkActive="active">Finish</button>
ts
constructor(private router: Router) { }
public submitSurvey(): void {
// Make sure everything is answered
const allOKClientSide: boolean = this.surveyService.checkEntireForm(this.thisSurvey);
if (allOKClientSide) {
if (this.surveyService.checkFormOnline(this.thisSurvey).subscribe()) {
this.router.navigateByUrl('/placeOne');
return;
}
}
this.router.navigateByUrl('/placeTwo');
}
You want your method to be called when the button is clicked. You can do this by using (clicK):
Instead of
[routerLink]="submitSurvey()"
do
(click)="submitSurvey()"
Then you use the router in your class to do the navigation:
constructor(private router: Router) {}
submitSurvey() {
// ...
this.router.navigate(['/placeOne']);
}

Render partial view with form in Modal on Html.ActionLink click

I have a page with table where each row has a link "Move".
On clicking of the link I am trying to get the controller GET method called which will in turn render the _MoveReportPartial view in a modal.
Once the user makes the selections in the modal the submit button should post to the Post method of the controller.
If I remove the class attribute (move-modal) from Html.ActionLink(...), it in effect disengages the js file and ignores it. Then it works by opening the _MoveReportPartial in a new window and then consequently posting to the correct method if user clicks submit.
I am trying to get it to open in the modal, but the js I have doesn't work and routes to the POST method instead on "Move" click.
EDIT
Why does the .load call the POST method instead of the GET? How can I change the js? (added event.preventDefault();, still the same behavior is observed)
The move link on the originating view looks like this:
<div class="d20 actionLink">
#Html.ActionLink("Move", "MoveReport", "ReportsWeb", new {id = item.ReportDefinitionId, newReport = false}, new {#class = "move-modal"})
</div>
I have a js file:
$(function () {
$('.move-modal').click(function () {
event.preventDefault();
$('<div/>').appendTo('body').dialog({
close: function (event, ui) {
dialog.remove();
},
modal: true
}).load(this.href, {});
});
});
My ReportsWebController looks like this:
[HttpGet]
public ActionResult MoveReport(Guid id, bool newReport)
{
//some code
return PartialView("_MoveReportPartial", model);
}
[HttpPost]
public ActionResult MoveReport(MoveReportModel Model)
{
try
{
//some code
}
catch (Exception exc)
{
InternetReportingTrace.Source.WriteError(exc);
throw;
}
return RedirectToAction("ListReports");
}
and my _MoveReportPartial looks like this:
<div id="dialog-confirm">
<div align="center">
<h2>Please Confirm</h2>
</div>
#using (Html.BeginForm("MoveReport", "ReportsWeb", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div tabindex="-1" role="dialog">
<div class="modal-content">
<p>Report #Model.Report.Name with ID #Model.Report.ReportDefinitionId </p>
<p>Will be moved to:</p>
#for (int i = 0; i < Model.MoveOptions.Count; i++)
{
<div class="radio">
<label><input type="radio" name="optradio">#Model.MoveOptions[i]</label>
</div>
}
<div>
<input type="submit" value="Move Report" />
</div>
</div>
</div>
}
I don't think you're preventing the default behaviour of the ActionLink properly.
Try:
$('.move-modal').click(function (event) {
event.preventDefault();
$('<div/>').appendTo('body').dialog({
close: function (event, ui) {
dialog.remove();
},
modal: true
}).load(this.href, {});
});
Because it's a jQuery handler, you can use event.preventDefault() instead of return false;. If your click handler uses return false to prevent browser navigation, it opens the possibility that the interpreter will not reach the return statement and the browser will proceed to execute the anchor tag's default behavior before that point. Using event.preventDefault() as the first line in the handler means you can guarantee that the default navigation behavior will not fire.
Secondly, your .load method call is wrong.
Change
.load(this.href, {});
to
.load(this.href);
The documentation at api.jquery.com/load states "The POST method is used if data is provided as an object; otherwise, GET is assumed." Because you're sending it an empty object, it assumes you want to use POST. There's no need to do this.

What would be the best way to read values from <h:selectOneMenu /> to javascript function?

I have jQuery modal div which displays on an on-click event....
<div id="time_scheduler" style="display: none;" title="Change Event Time" class="dialog">
<div class="block">
<h:form>
<span>Select Shift</span>
<p></p>
<h:selectOneMenu value="#{fieldController.shift}">
<f:selectItems itemLabel=" #{s.shiftName} #{s.startTime} to #{s.endTime}" var="s" value="#{fieldController.allShiftUnfiltered}" />
<f:converter converterId="shconvert" />
</h:selectOneMenu>
<p></p>
<h:commandButton onclick="getShift('#{request.contextPath}/changeEvent?','#{fieldController.shift.startTime}','#{fieldController.shift.endTime}');" styleClass="btn btn-small" value="change" />
</h:form>
</div>
</div>
and also a javascript function in a js file which gets called in a commandButton , the problem is each time the page displays , i get a null on the selectOneMenu after i click, then later i get the value, although its inconsistent,
function getShift(url,start_time,end_time){
console.log('starttime is '+start_time); //start time is null on page first load
console.log('endtime is '+end_time); //end time is null on first page load
$.ajax({
url: url + 'event_id=' + event_id + '&start_time=' + start_time + '&end_time=' + end_time,
cache: false,
success: function(value) {
console.log(value);
}
});
}
I have a converter class
#FacesConverter(value = "shconvert")
public class ShiftConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
AdminEJB adm;
try {
adm = (AdminEJB) new InitialContext().lookup("java:global/ffm/AdminEJB");
return adm.findShift(value);
} catch (NamingException ex) {
return null;
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}
}
which pretty much does the conversion at a postconstruct level, what could really be the best way to pass this values to the javascript function each time the is changed ?
The way the commandButton is set up will make it use the last submitted values to call the javascript function. Before addressing this issue, we may want to understand the relationship between EL, JSF, and Javascript. JSF takes the facelet code and turns it into HTML. Any EL statements are resolved on the server side at that time. So, when it's all said and done, we have an HTML page that we can inspect in our favorite browser. Now comes Javascript, which has no awareness of JSF, so it works solely on the rendered HTML page.
With that in mind, we can see why the code above wouldn't work. The EL statements used as argument to the getShift Javascript function will only be resolved when that part of the page is rerendered by the server.
It look like the objective here is to call a non-JSF servlet asynchronously when the button is clicked. I would go about this a little differently. Have the commandButton call a JSF method asynchronously, and the method can reach out to the custom servlet.
<div id="time_scheduler" style="display: none;" title="Change Event Time" class="dialog">
<div class="block">
<h:form>
<span>Select Shift</span>
<p></p>
<h:selectOneMenu value="#{fieldController.shift}">
<f:selectItems itemLabel=" #{s.shiftName} #{s.startTime} to #{s.endTime}" var="s" value="#{fieldController.allShiftUnfiltered}" />
<f:converter converterId="shconvert" />
</h:selectOneMenu>
<p></p>
<h:commandButton styleClass="btn btn-small" value="change">
<f:ajax execute="#form" listener="#{someBean.callServlet()} />
</h:commandButton>
</h:form>
</div>
Then, create a backing bean with a method to call the servlet
#Named
public class SomeBean {
#Inject FieldController fieldController;
public String callServlet() {
Object startTime = fieldController.shift.startTime;
Object endTime = fieldController.shift.endTime;
//Call the servlet here
return null;
}
}
Here's an example on calling a servlet from java.

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";
}

Categories