how to link one visualforce page from another visualforce page? - apex-code

I want to add two numbers that are given in a vf page text boxes. I want to print the result in another vf page by clicking the button (add button) in first page.

You can do this by routing to the next page in Visualforce and passing the value you want to display as a parameter. Something like this in Apex should work:
PageReference gotoPage()
{
PageReference pr = Page.YourSecondVFPage;
pr.getParameters().put('secondnumber', '' + this.secondNumber);
pr.setRedirect(true);
return pr;
}
Then in Visualforce:
<apex:commandButton value="Go!" action="{!gotoPage}"/>

I think you might want to try using the same controller on both pages. That way you don't have to pass all that data, assuming you have more than just a couple of fields to maintain, as url parameters or have to store the data somewhere if you don't have to.
If both pages are using the same controller and when you redirect the user using a PageReference make sure to set the redirect value to false, otherwise Salesforce treats as a new request and starts the page with a new instance of the controller.
The sample code below lets the user type some text into a field and then when print view is clicked it renders a PDF using that same information. No data was saved to database.
Controller
public with sharing class MyController {
public string MyData {get;set;}
public MyController() {
MyData = '';
}
public PageReference printView() {
PageReference oPageRef = Page.MyPage2;
oPageRef.setRedirect(false);
return oPageRef;
}
}
Page 1:
<apex:page controller="MyController">
<apex:sectionheader title="Test" subtitle="My Page"/>
<apex:form id="formData">
<apex:pageBlock title="My Data">
<apex:pageBlockButtons >
<apex:commandButton value="Printable View" action="{!printView}" />
</apex:pageBlockButtons>
<apex:pageBlockSection >
<apex:pageBlockSectionItem >
<apex:outputLabel value="My Data"/>
<apex:inputTextArea value="{!MyData}" />
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
Page 2:
<apex:page controller="MyController"
renderAs="pdf">
{!MyData}
</apex:page>

Related

ASP.NET Core MVC submit form in partial view / ViewComponent

I have a menu and a content area which displays content based on the selected item in the menu. Since the user is allowed to change the structure of the main menu, I decided that everything will be on page /home/index and will have a guid assigned to the content which needs to be shown. I started with the idea to introduce partial views, but realized that ASP.NET Core doesn't have RenderAction anymore and was replaced by ViewComponents.
So I used ViewComponents and everything works fine, except that I've stumbled on a situation where I need to have a component as a submit form.
In an example: One menu item is the menu is a component that shows a list of users. Another menu item is a component that creates a new user. On create user component I'll have a form that needs to be filled and on successful submit, I want to redirect the user to the component that shows a list of users. In the case of unsuccessful submit, error, wrong input I would of course not want to redirect the user to the list of users.
Since ViewComponents' job is to display view, how should I approach this issue? I'm looking for pointers in the right direction.
I have little experience in this field so any help would be appreciated.
UPDATE
In Index.cshtml:
<tbody>
#foreach (string item in Model.Components)
{
<tr>
<td>
<div class="col-md-3">
#await Component.InvokeAsync(#item)
</div>
</td>
</tr>
}
</tbody>
This is inside the content area. Components are string names of components I'd like to show in the content area (currently listed one after the other).
My ViewComponent which will get called when I click on the menu item to display the form:
public class TestFormViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync()
{
return View("_TestForm", new TestModelPost());
}
}
My _TestForm.cshtml component:
#model TestModelPost
<form asp-controller="Home" asp-action="TestPost" method="post">
<label asp-for="Name"></label>
<input asp-for="Name" /><br />
<label asp-for="Surname"></label>
<input asp-for="Surname" /><br />
<button type="submit">Go</button>
</form>
And the action TestPost called:
[HttpPost]
public IActionResult TestPost(TestModelPost model)
{
// Save model data, etc
// !ModelState.IsValid -> go back to form
// Success -> go to specific id
return RedirectToAction("Index", new { id = 1 });
}
How should I approach this? Or rather, am I even on the right track? I'm not sure how I would go "back" to that view I created in my _TestForm component in case the input was incorrect.
View components, just like child actions before them in ASP.NET MVC do not support POSTs. You need a full fledged action to handle the form post, which will need to return a full view. Essentially, you just need to think about it more abstractly.
A view component is just ultimately a means of dumping some HTML into the eventual response. When the full response is returned to the client, there's no concept of what was a view component, a partial view, etc. It's just an HTML document. Part of that HTML document is your form. That form will have an action, which ultimately should be a route that's handled by one of your controller actions. A traditional form post cause the entire browser view to change, so the response from this action should either be a full view or a redirect to an action that returns a full view. The redirect is the more appropriate path, following the PRG pattern. It is then the responsibility of that view that is eventually returned to determine how the content is constructed, using view components, partials, etc. as appropriate.
Long and short, this really has nothing to do with your view component at all. All it is doing is just dropping the form code on the page.
For forms like this that are part of the layout, it's usually best to include a hidden input that contains a "return URL" in the form. The action that handles the form, then can redirect back to this URL after doing what it needs to do, in order to give the semblance that the user has stayed in the same place.
Kindly refer to the following link:
https://andrewlock.net/an-introduction-to-viewcomponents-a-login-status-view-component/
it might be of help
public class LoginStatusViewComponent : ViewComponent
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
public LoginStatusViewComponent(SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> userManager)
{
_signInManager = signInManager;
_userManager = userManager;
}
public async Task<IViewComponentResult> InvokeAsync()
{
if (_signInManager.IsSignedIn(HttpContext.User))
{
var user = await _userManager.GetUserAsync(HttpContext.User);
return View("LoggedIn", user);
}
else
{
return View();
}
}
}
Our InvokeAsync method is pretty self explanatory. We are checking if the current user is signed in using the SignInManager<>, and if they are we fetch the associated ApplicationUser from the UserManager<>. Finally we call the helper View method, passing in a template to render and the model user. If the user is not signed in, we call the helper View without a template argument.
As per your code segment you can try to modify it as follows:
public class TestFormViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync()
{
if (_signInManager.IsSignedIn(HttpContext.User))
{
//user list display
return View("_TestForm", new TestModelPost());
}
else
{
return View();
}
}
}

Add and remove textbox at runtime in mvc3

In my page there is one textbox by default and one add button beside it. I need to add the another textbox when user click Add button. And there should be two buttons Add and Remove beside newly added text box. And same process goes on i.e., user can add Textbox using Add button and remove it using remove button.
I am new to mvc 3 so i am confused how to proceed. Is there any way like placeholder in asp.net so that we can add control at runtime.
Any suggestion and idea will be helpful to me
MVC is a very "hands-off" framework compared to Web Forms, so you're free to add the new textboxes how you like. Note that "controls" don't exist in MVC.
Here's how I'd do it:
Model:
class MyModel {
public Boolean AddNewTextBox { get; set; }
public List<String> MultipleTextBoxes { get; set; } // this stores the values of the textboxes.
}
View (I prefer the Web Forms view engine, I'm not a fan of Razor):
<% for(int i=0;i<Model.MultipleTextBoxes.Count;i++) { %>
<%= Html.TextBoxFor( m => m.MultipleTextBoxes[i] ) /* this might look like magic to you... */ %>
<% } %>
<button type="submit" name="AddNewTextbox" value="true">Add New Textbox</button>
<button type="submit">Submit form</button>
Controller:
[HttpPost]
public ActionResult MyAction(MyModel model) {
if( model.AddNewTextBox ) model.MultipleTextBoxes.Add("Yet another");
else if( ModelState.IsValid ) {
// your regular processing
}
}
You can also add more textboxes with Javascript and it work perfectly fine. All that matters is the HTML input elements. There's no cryptic viewstate. MVC is stateless.
Note that because I used <button type="submit"> my example will not work reliably in Internet Explorer 6-8 (sucks, I know), but you can replace them with <input type="submit"> with no ill-effects.
This requires some Javascript/JQuery... The following is a sketch only, but will hopefully be useful as a general approach.
The remove button
You want to render a button that can target its own container for removal. To do that, use some markup like this:
<div class="item-container">
<input type="button" onclick="removeItem(this)" />
</div>
And the Javascript for removeItem:
<script>
function removeItem(element) {
// get the parent element with class "item-container" and remove it from the DOM
$(element).find(".item-container").remove();
}
</script>
The add button
You could either use a partial view with Ajax, or use straight Javascript; which one is best likely depends on whether you need a round-trip to the server to create a new item. Let's say you need to go the the server to generate a new ID or something.
First, create a partial view and corresponding controller action; this should contain the remove button as above, as well as the text box and add button.
Now, create an Ajax form on your main page that gets invoked when you click Add:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm("New", new AjaxOptions() { UpdateTargetId="ajaxTarget", HttpMethod = "GET" })) {
<input type='submit' value='Add New' />
}
<div id="ajaxTarget"></div>
This code fetches your partial view (from the action New in the current controller) and adds the result to the ajaxTarget element.
Note The Ajax form requires Unobtrusive Ajax, which you can install via Nuget: Install-Package JQuery.Ajax.Unobtrusive.

Visualforce - Clickable DataTable Cells - How to get Column and Row information

I'd like to create a datatable where each cell is clickable. I'm assuming that I can probably fill each cell with apex:outputlink and that takes care of the clickable part as well as calling my controller for each click. The big question I need an answer for is how do I pass information to my apex controller about which cell (i.e.: which row and which column) was actually clicked.
Any help for this is highly appreciated.
Its easy. Just define an action function to catch the values from the dataTable:
1) First defining three vars tht we will pass to controller: raw-id, cell-value, cell-type
public String clickedRowId { get; set; }
public String clickedCellValue { get; set; }
public String clickedCellType { get; set; }
public PageReference readCellMethod(){
System.debug('#### clickedRowId: ' + clickedRowId);
System.debug('#### clickedCellValue: ' + clickedCellValue);
System.debug('#### clickedCellType: ' + clickedCellType);
return null;
}
2) Second we create an action function, that calls our apex method an pass three vars to it:
<apex:actionFunction name="readCell" action="{!readCellMethod}">
<apex:param name="P1" value="" assignTo="{!clickedRowId}"/>
<apex:param name="P2" value="" assignTo="{!clickedCellValue}"/>
<apex:param name="P3" value="" assignTo="{!clickedCellType}"/>
</apex:actionFunction>
3) And third we create our dataTable, where each cell has onClick listener:
<apex:pageBlockTable value="{!someArray}" var="item">
<apex:column value="{!item.name}" onclick="readCell('{!item.id}','{!item.name}','name')" />
<apex:column value="{!item.CustomField1__c}" onclick="readCell('{!item.id}','{!item.CustomField1__c}','custom1')" />
<apex:column value="{!item.CustomField2__c}" onclick="readCell('{!item.id}','{!item.CustomField2__c}','custom2')" />
</apex:pageBlockTable>
We can access our actionFunction like any other JavaScript function. If user clicks on the cell - three vars will be send to the actionFunction and then to controller.

Best method to pass value in MVC

I am still new to MVC, so sorry if this is an obvious question:
I have a page where the user can choose one of several items. When they select one, they are taken to another form to fill in their details.
What is the best way to transfer that value to the form page?
I don't want the ID of the item in the second (form) pages URL.
so it's /choose-your-item/ to /redemption/ where the user sees what was selected, and fills the form in. The item selected is displayed, and shown in a hidden form.
I guess one option is to store in a session before the redirect, but was wondering if there was another option.
I am using MVC3
Darin Dimitrov's answer would be best if you don't need to do any additional processing before displaying the /redemption/ page. If you do need to some additional processing, you're going to have to use the TempDataDictionary to pass data between actions. Values stored in the TempDataDictionary lasts for one request which allows for data to be passed between actions, as opposed to the values stored in the ViewDataDictionary which only can be passed from an action to a view. Here's an example below:
public ActionResult ChooseYourItem()
{
return View();
}
[HttpPost]
public ActionResult ChooseYourItem(string chosenItem)
{
TempData["ChosenItem"] = chosenItem;
// Do some other stuff if you need to
return RedirectToAction("Redemption");
}
public ActionResult Redemption()
{
var chosenItem = TempData["ChosenItem"];
return View(chosenItem);
}
If you don't want the selected value in the url you could use form POST. So instead of redirecting to the new page, you could POST to it:
#using (Html.BeginForm("SomeAction", "SomeController"))
{
#Html.DropDownListFor(...)
<input type="submit" value="Go to details form" />
}
To help others, this is how I resolved my issue of needing multiple buttons posting back, and wanting to pass a different Id each time.
I have a single form on the page, that posts back to my controller:
The Form:
#using (Html.BeginForm("ChooseYourItem", "Item", FormMethod.Post))
{
And the code
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChooseYourItem(string itemId)
{
TempData["ITEMID"] = itemId
return RedirectToAction("Create", "Redemption");
}
Then, inside the form, I create buttons whose name == "itemId", but has a different value each time.
For example
<strong>Item 1</strong>
<button value="123" name="itemid" id="btn1">Select</button>
<strong>Item 2</strong>
<button value="456" name="itemid" id="btn2">Select</button>

Redirection in controller in MVC 3 with Razor

I need a little help. I'm trying to make a little project in MVC 3 with Razor. A page with 2 buttons: Button 1 and Button 2. When I click on Button 1 I want to go at Page 1. The same with Button 2 ( to Page 2). It's not difficult, BUT I want the redirection to be made in Controller, not in View (cshtml). I know that I need to use ActionName and RedirectToAction, but I don't know how. Please help me!
What you'll need to do is check which button was pressed in the HttpPost part of the controllers action then redirect accordingly.
As a very basic example you could add two
<input type="submit" name="submit" value="<val>">
controls into your forms view each having the same name and a different value (instead of ) then add a string parameter called submit to the HttpPost action. Assuming the buttons have values "button1" and "button2" Then in your action's code you could use:
if(submit == "button1") {
RedirectToAction("Page1");
} else {
RedirectToAction("Page2");
}
to redirect based on which button was pressed
This is a simplified example, but I think you will get my meaning. You simply need to name your buttons and check the formcollection to see which exists in the collection thus indicating which what clicked. see code below:
#using (Html.BeginForm("Test", "Home", FormMethod.Post))
{
<input type="submit" value="Go 1" name="go-1" />
<input type="submit" value="Go 2" name="go-2" />
}
and now the Action implementation.
[HttpPost]
public ActionResult Test(FormCollection collection)
{
if (collection.AllKeys.Contains("go-1")) return View("Page1");
if (collection.AllKeys.Contains("go-2")) return View("Page2");
return View("Index");
}
and thats it.
In your controller action for page 1, you can use RedirectToAction:
public ActionResult Process()
{
// do processing
// redirect to page 2
return this.RedirectToAction("Index", "Page2");
}
You can invoke the Process action from the Page 1 button using either a GET or POST request, depending on if the Process action is idempotent. E.g your page 1 view:
#Html.BeginForm("Process", "Page1", FormMethod.Post)
{
<input type="submit" name="button" value="Submit" />
}
Alternatively, you could use an ActionLink:
#Html.ActionLink("Redirect to Page 2", "Process", "Page1")

Resources