6

Here's the situation.

I have a save, and a print button :

<input name="btnSubmit" type="submit" value="Save" /> 
<input name="btnSubmit" type="submit" value="Print"/> @*Redirect to Action("Print", "controler")*@

But the print button has to open a new tab. If it was just me, I obviously know I have to save before printing... it would not be an issue. I could use this link with target blank instead :

<a target="_blank" href="@Url.Action("Print", "controler", new { id = Model.id })" type="submit" value="Print" > Print</a>

Easy, but now some users think that the print button should ALSO save the page. Because they don't push save... they just print and the model changes are lost because I can't call the post action in my print link... it's a link.

I thought, at first, that I could make an asynchronous call to a save fonction, but my model is way too big, it requires the post back of it's own action (right ?)

Went through this :

How do I use Target=_blank on a response.redirect?

And i'm not sure if it really help in MVC... right now i'm stuck here :

[HttpPost]
public ActionResult MyForm(string btnSubmit, formModel model)
{
    if (btnSubmit == "Print")
    {
        dbSave(model);
        return RedirectToAction("Print", "controler"); // Won't open new tab... 
    }
}
Antoine Pelletier
  • 3,164
  • 3
  • 40
  • 62

1 Answers1

10

at first when user click on print button i post my data by ajax request and after successfully done i open a new tab.

Example:

$.ajax({
    url: "@Url.Action("create", "Post")",
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify({ model: model})
}).done(function(result){
window.open('@Url.Action("Print", "controler", new { id = Model.id })', '_blank').focus();
}); 

OR

You want to write something like your example in http response then you can do something like

  HttpContext.Current.Response.Write( @"<script type='text/javascript' language='javascript'>window.open('page.html','_blank').focus();</script>");

UPDATE

I have added a full flow of a testing project below.

Example:

Model:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ProductCode { get; set; }
    public decimal Price { get; set; }
}

Controller:

 public class ProductController : Controller
    {
        // GET: Product
        public ActionResult Index()
        {
            return View();
        }


        // GET: Product/Create
        public ActionResult Save()
        {
            var model = new Product();
            return View(model);
        }

        // POST: Product/Create
        [HttpPost]
        public ActionResult Save(Product model, string saveButton)
        {
            if (ModelState.IsValid)
            {
                //do something 
                return
                    Json(
                        new
                        {
                            redirectTo = Url.Action("Index", "Product", new { Area = "" }),
                            OpenUrl = Url.Action("Print", "Product", new { Area = "" })

                        });
            }
            return View(model);
        }
        public ActionResult Print()
        {
            return View();
        }
}

Save.cshtml:

@model Product

@{
    ViewBag.Title = "Save";
}

<h2>Save</h2>
@Html.Hidden("saveButton","Test")@*Change Test to your value or change it to using JavaScript*@
@using (Html.BeginForm("Save", "Product", new {area = ""}, FormMethod.Post, new {id = "fileForm", name = "fileForm"}))
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Product</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ProductCode, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ProductCode, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProductCode, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <button type="button" class="btn btn-primary" id="btnSave">Save</button>
                <button type="button" class="btn btn-default">Print</button>
            </div>
        </div>
    </div>
}

Script:

<script>
        $("#btnSave").click(function() {
            $.ajax({
                url: $("#fileForm").attr('action'),
                type: $("#fileForm").attr('method'),
                beforeSend: function() {
                },
                data: $("#fileForm").serialize() + "&saveButton=" + $("#saveButton").val()
            }).done(function(result) {
                if (result.OpenUrl) {
                    window.open(result.OpenUrl, '_blank');
                }
                if (result.redirectTo) {
                    setTimeout(function() {
                            window.location.href = result.redirectTo;
                        },2000);
                }


            });
        })

    </script>
Chandan Kumar
  • 4,570
  • 4
  • 42
  • 62
Ashiquzzaman
  • 5,129
  • 3
  • 27
  • 38
  • I use like something in several years. – Ashiquzzaman May 18 '17 at 19:25
  • @AntoinePelletier It is not possible to open a new tab from a controller, that is a UI concern. As such, I think this answer is on the right path with the AJAX post however some additional checks (such as did the AJAX post succeed) should be put in place. Also, you could (should?) put a click handler directly on the `` tag which you could then pull the HREF from the clicked object without having razor markup in your JS for the print URL. I would stay away from the second method in MVC as it just gives me a dirty feeling :) – Tommy May 24 '17 at 15:14
  • @Tommy my model contains about 200 fields, do you see any limitations ? Also is this https://stackoverflow.com/questions/11171746/reverse-of-json-stringify the right way to retreive my datas...? – Antoine Pelletier May 24 '17 at 15:36
  • Not that I am aware of and this answer (https://stackoverflow.com/questions/1262376/is-there-a-limit-on-how-much-json-can-hold) seems to agree. It may take a bit more time to serialize the form, but you would need to test that on your end to see if its an issue. For your second question, would use the `form.serialize()` method like in this answer's Index.html Javascript section (https://stackoverflow.com/a/30680773/130387) - the server side code is PHP but the JS is still valid for MVC/.NET – Tommy May 24 '17 at 15:46
  • Thanks, it solve my first concern. For my second one though, i was talking about how to retrieve my model on server side, in C#. I guess `FormModel obj = JSON.parse(str);` will do the trick. – Antoine Pelletier May 24 '17 at 19:09
  • Is your view strongly typed and does all of your form fields come from that model? If so, you don't have to do anything, the MVC model binder will translate for you. For instance, if your ViewModel is of type `SuperLargeFormViewModel`, your action method would be `public ActionResult MyForm(string btnSubmit, SuperLargeFormViewModel model)` – Tommy May 24 '17 at 20:20
  • @AntoinePelletier I update my answer. can you please try it? – Ashiquzzaman May 25 '17 at 06:54
  • @Ashiquzzaman inspired by the code you provided, i managed to do it, but chrome will try to block the "pop up" obviously. But it work, thanks ! – Antoine Pelletier May 25 '17 at 18:08