I am new to BreezeJS, and have recently created a project that is up and running. I am able to use Breeze to query data from my SQL server without a problem. However, whenever I try to save changes, the changes do not save. I have verified, in VS 2012, that the JavaScript save function is actually called, however the HttpPost method on the server side is never called.
Here is the Breeze Controller that I have set up:
using System.Linq;
using System.Web.Http;
using Newtonsoft.Json.Linq;
using Breeze.WebApi;
using FitnessTracker.Models;
namespace FitnessTracker.Controllers
{
[BreezeController]
public class BreezeController : ApiController
{
private readonly EFContextProvider<FitnessTrackerContext> _fitnessContext =
new EFContextProvider<FitnessTrackerContext>();
//
// GET: /Breeze/
[HttpGet]
public string Metadata()
{
return _fitnessContext.Metadata();
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _fitnessContext.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<FitnessEquipment> FitnessEquipments()
{
return _fitnessContext.Context.FitnessEquipments;
}
}
}
Here is the save function that I am using:
function saveChanges() {
return manager.saveChanges()
.fail(saveFailed);
}
Here is the HTML:
<div class="box-body form" data-bind="foreach: exercises">
<input type="text" class="txt-m g2" data-bind="text: EquipmentName" />
<input type="text" class="txt-m g1" data-bind="text: EquipmentLevel" />
<input type="text" class="txt-m g2" data-bind="text: DurationSeconds" />
<input type="text" class="txt-m g2" data-bind="text: Weight" />
<input type="text" class="txt-m g4" data-bind="text: DateTime" />
<br class="clear" />
</div>
Save Changes
Thanks in advance for your help!!
Edit 9/12/2013:
I have fixed it thanks to Jay's help!!
The problem is that I was binding on the text instead of the value. I changed the html to:
<div class="box-body form" data-bind="foreach: exercises">
<input type="text" class="txt-m g2" data-bind="value: EquipmentName" />
<input type="text" class="txt-m g1" data-bind="value: EquipmentLevel" />
<input type="text" class="txt-m g2" data-bind="value: DurationSeconds" />
<input type="text" class="txt-m g2" data-bind="value: Weight" />
<input type="text" class="txt-m g4" data-bind="value: DateTime" />
<br class="clear" />
</div>
It is now saving without a problem. Thanks Jay for your help!
Have you confirmed that you are actually changing/or adding an entity within the EntityManager on the client? You can call the EntityManager's hasChanges method to confirm. Breeze does not attempt to call the server if there are no changes to save.
So try something like
if (manager.hasChanges()) {
manager.saveChanges()
.fail(saveFailed);
} else {
// my guess is that you will get here.
}
My guess is that you either have a binding issue or have not queried or created an entity that requires saving.
Related
I have a Likert Survey generator where a dynamic number of questions can be entered - then a user goes through and answers each question with 4 radio buttons (Strongly Disagree, Disagree, Agree, Strongly Agree).
I can output them easily enough - but can they be model bound on the post back or do I have to traverse the posted form elements (ie not use model binding)?
I've Googled a lot and can find no solution - is it posible?
Thanks.
If you want to bind a list in view,here is a demo about binding a list with input names:
Model:
public class Qusetion
{
public string Content { get; set; }
public string Answer { get; set; }
}
View:
<form method="post">
<div>
<label>question1</label>
<input name="list[0].Content" value="question1" hidden/>
<div>
<input type="radio" name="list[0].Answer" value="Strongly Disagree" />Strongly Disagree
<input type="radio" name="list[0].Answer" value="Disagree" />Disagree
<input type="radio" name="list[0].Answer" value="Agree" />Agree
<input type="radio" name="list[0].Answer" value="Strongly Agree" />Strongly Agree
</div>
</div>
<div>
<label>question2</label>
<input name="list[1].Content" value="question2" hidden/>
<div>
<input type="radio" name="list[1].Answer" value="Strongly Disagree" />Strongly Disagree
<input type="radio" name="list[1].Answer" value="Disagree" />Disagree
<input type="radio" name="list[1].Answer" value="Agree" />Agree
<input type="radio" name="list[1].Answer" value="Strongly Agree" />Strongly Agree
</div>
</div>
<div>
<label>question3</label>
<input name="list[2].Content" value="question3" hidden/>
<div>
<input type="radio" name="list[2].Answer" value="Strongly Disagree" />Strongly Disagree
<input type="radio" name="list[2].Answer" value="Disagree" />Disagree
<input type="radio" name="list[2].Answer" value="Agree" />Agree
<input type="radio" name="list[2].Answer" value="Strongly Agree" />Strongly Agree
</div>
</div>
<input type="submit" value="submit" />
</form>
Controller:
public IActionResult BindList(List<Qusetion> list)
{
return View();
}
result:
Update:
If you want to bind with loop.you can pass list to view.And the code will work is because .net core bind model with name attribute.And because you want to bind list,so the name will be like list[index].xxx.
Here is a demo with loop:
View:
#model IEnumerable<Qusetion>
<form method="post">
#{ var i = 0;}
#foreach (var question in Model)
{
<div>
<label>#question.Content</label>
<input name="list[#i].Content" value="#question.Content" hidden />
<div>
<input type="radio" name="list[#i].Answer" value="Strongly Disagree" />Strongly Disagree
<input type="radio" name="list[#i].Answer" value="Disagree" />Disagree
<input type="radio" name="list[#i].Answer" value="Agree" />Agree
<input type="radio" name="list[#i].Answer" value="Strongly Agree" />Strongly Agree
</div>
</div>
i++;
}
<input type="submit" value="submit" />
</form>
Controller:
public IActionResult BindList(List<Qusetion> list)
{
List<Qusetion> list1 = new List<Qusetion> { new Qusetion { Content = "question1" }, new Qusetion { Content = "question2" }, new Qusetion { Content = "question3" } };
return View(list1);
}
result:
I need to display 6 types of tests on my view and allow the user to check as many tests as they'd like to complete. I will then need to send their response to my controller so I can add that information to a database using the entity framework.
my View:
#using (Html.BeginForm("Quote", "Customers", FormMethod.Post))
{
<label for="test1"> BP</label>
#Html.CheckBox("test1", true)<br />
<label for="test2"> DS</label>
#Html.CheckBox("test2")<br />
<label for="test3"> IS</label>
#Html.CheckBox("test3")<br />
<label for="test4" class="iput">PS</label>
#Html.CheckBox("test4")<br />
<label for="test5">PF</label>
#Html.CheckBox("test5")<br />
<label for="test6">CS</label>
#Html.CheckBox("test6")<br />
<input type="submit" value="Begin Quote" class="btn btn-default" style="padding-left: 20px" />
}
and my controller method:
[HttpPost]
public ActionResult Quote(FormCollection collection )
{
if (!string.IsNullOrEmpty(collection["test1"]))
{
string checkResp = collection["test1"];
bool checkRespB = Convert.ToBoolean(checkResp);
}
return View("Index");
}
I am running into an issue when debugging...The collection["test1"] is returning a "true, false" value instead of the actual checked value of the checkbox. I cannot seem to get the form to collect the actual statuses of the check boxes.
I have tried other options but none have seemed to work. Any help is greatly appreciated!
I have searched for hours for this without finding an answer, so I'm asking your help (I'm a beginner in web development (and in Asp.Net MVC)).
I want to create a simple data permutator (for example you enter 3 datas "a, b, and c", and I give you the possible permutations between these 3 datas : "abc; acb; bac; bca; cab; cba").
I have tried the following code, but it does not work (I have an HTTP 404 error).
<form method="post">
<div class="col-md-4 input-group">
<div class="input-group-addon">1</div>
<input type="text" name="firstData" class="form-control" placeholder="First Data" maxlength="50" required />
</div>
<div class="col-md-4 input-group">
<div class="input-group-addon">2</div>
<input type="text" name="secondData" class="form-control" placeholder="Second Data" maxlength="50" required />
</div>
<div class="col-md-4 input-group">
<div class="input-group-addon">3</div>
<input type="text" name="thirdData" class="form-control" placeholder="Third Data" maxlength="50" required />
</div>
<div class="col-md-12 mainAction centerbloc">
<input type="submit" value="Permutate the data" class="btn btn-success register-button-slider" href="">
</div>
</form>
And then below, I want to display the result in the same page, like this :
#{ if (IsPost)
{
string firstdata = Request.Form["firstData"];
string seconddata = Request.Form["secondData"];
string thirddata = Request.Form["thirdData"];
<p>
#firstdata #seconddata #thirddata<br />
#seconddata #firstdata #thirddata<br />
</p>
}
}
I haven't put anything special in my controller (maybe the mistake is here?) :
namespace Blogs.Controllers
{
public class ToolsController : Controller
{
[Route("tools/datapermutator", Name = "DataPermutator"), HttpGet]
public ActionResult DataPermutator()
{
return View();
}
}
}
If you have a way to do it, it would be very helpful, thank you in advance!
I have a basic form for which I want to handle buttons inside the form by calling the ActionResult method in the View's associated Controller class. Here is the following HTML5 code for the form:
<h2>Welcome</h2>
<div>
<h3>Login</h3>
<form method="post" action= <!-- what goes here --> >
Username: <input type="text" name="username" /> <br />
Password: <input type="text" name="password" /> <br />
<input type="submit" value="Login">
<input type="submit" value="Create Account"/>
</form>
</div>
<!-- more code ... -->
The corresponding Controller code is the following:
[HttpPost]
public ActionResult MyAction(string input, FormCollection collection)
{
switch (input)
{
case "Login":
// do some stuff...
break;
case "Create Account"
// do some other stuff...
break;
}
return View();
}
you make the use of the HTML Helper and have
#using(Html.BeginForm())
{
Username: <input type="text" name="username" /> <br />
Password: <input type="text" name="password" /> <br />
<input type="submit" value="Login">
<input type="submit" value="Create Account"/>
}
or use the Url helper
<form method="post" action="#Url.Action("MyAction", "MyController")" >
Html.BeginForm has several (13) overrides where you can specify more information, for example, a normal use when uploading files is using:
#using(Html.BeginForm("myaction", "mycontroller", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
< ... >
}
If you don't specify any arguments, the Html.BeginForm() will create a POST form that points to your current controller and current action. As an example, let's say you have a controller called Posts and an action called Delete
public ActionResult Delete(int id)
{
var model = db.GetPostById(id);
return View(model);
}
[HttpPost]
public ActionResult Delete(int id)
{
var model = db.GetPostById(id);
if(model != null)
db.DeletePost(id);
return RedirectToView("Index");
}
and your html page would be something like:
<h2>Are you sure you want to delete?</h2>
<p>The Post named <strong>#Model.Title</strong> will be deleted.</p>
#using(Html.BeginForm())
{
<input type="submit" class="btn btn-danger" value="Delete Post"/>
<text>or</text>
#Url.ActionLink("go to list", "Index")
}
Here I'm basically wrapping a button in a link. The advantage is that you can post to different action methods in the same form.
<a href="Controller/ActionMethod">
<input type="button" value="Click Me" />
</a>
Adding parameters:
<a href="Controller/ActionMethod?userName=ted">
<input type="button" value="Click Me" />
</a>
Adding parameters from a non-enumerated Model:
<a href="Controller/ActionMethod?userName=#Model.UserName">
<input type="button" value="Click Me" />
</a>
You can do the same for an enumerated Model too. You would just have to reference a single entity first. Happy Coding!
Context
Let`s say i have:
In layout Site.Master:
<div class="leftColumn">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
<div class="rightColumn">
<% Html.RenderPartial("_Login"); %>
<asp:ContentPlaceHolder ID="SideContent" runat="server" />
</div>
Login partialView looks like:
<form action="/myApp/Account/Login" method="post">
<input name="name" />Name<br />
<input name="password" type="password" />Password<br />
<button>Login</button>
</form>
Is it possible to update only login widget form, not the entire content page?
If you are referring to a http post, only a post initiated (it can also be initiated by javascript) by a submit button from within the form will be posted to the server.
If your forms are nested then this won't work. The outer form will always post to the server.
In the sample HTML below, clicking on the submit button on the first form will not send the values from the second form to the server. Likewise, clicking the second submit button won't post the values from the first form.
<html>
...
<body>
<div>
<form action="/Login/Login" method="post">
<input type="text" name="username" value="" />
<input type="text" name="passowrd" value="" />
<input type="submit" name="login" value="Login" />
</form>
<form action="/Login/AdminLogin" method="post">
<input type="text" name="username" value="" />
<input type="text" name="passowrd" value="" />
<input type="submit" name="login" value="Login Admin" />
</form>
</div>
</body>
</html>
If you only wish to update/change one of the form section, then no this can not be done without using javascript and performing a javascript post(aka Ajax).
If you build a controller method that accepts a FormCollection and your view has two forms defined, the formcollection returned will either be populated with values from form A or form B. You can inspect the formCollection and branch your logic based on the value therein. If you want the be very explicit you could have the same hidden variable occur in both forms with a value that would help your make your choice.
That's one approach. there are a few ways to deal with this I'm sure.
If you have two simple forms, you can use this aproach:
You create two different partial views.
#model CustomerInfoModel
#using (Ajax.BeginForm("CustomerInfo", "Customer", new AjaxOptions { HttpMethod = "Post", OnBegin = "InfoLoading", OnComplete = "InfoCompleted" }, new { id = "info", #class = "form-horizontal" }))
{
<input type="text" class="form-control" name="Name" id="Name" value="#Model.Name" />
<input type="email" class="form-control" name="Email" id="Email" value="#Model.Email" />
<button type="submit" id="save-info" class="btn-medium red">Save</button>
}
and
#model CustomerPasswordChangeModel
#using (Ajax.BeginForm("CustomerPasswordChange", "Customer", new AjaxOptions { HttpMethod = "Post", OnBegin = "InfoLoading", OnComplete = "InfoCompleted" }, new { id = "change", #class = "form-horizontal" }))
{
<input type="password" class="form-control" name="OldPassword" id="OldPassword" value="" />
<input type="password" class="form-control" name="NewPassword" id="NewPassword" value="" />
<button type="submit" id="save-change" class="btn-medium red" autocomplete="off">Save</button>
}
In your parent view,
#Html.Partial("CustomerInfo", Model.CustomerInfo)
and
#Html.Partial("CustomerPasswordChange", Model.CustomerPasswordChange)
In Controller:
[HttpPost]
public ActionResult CustomerInfo([Bind(Include = "Name,Email")] CustomerInfoModel model)
{
if (ModelState.IsValid)
return new Json(new { success=true, message="Updated.", errors=null);
// do you logic
return new Json(new { success=false, message="", errors=getHtmlContent(ModelState.Values.SelectMany(v => v.Errors).ToList(), "ModelError"));
}
[HttpPost]
public ActionResult CustomerPasswordChange([Bind(Include = "OldPassword,NewPassword")] CustomerPasswordChangeModel model)
{
if (ModelState.IsValid)
return new Json(new { success=true, message="Updated.", errors=null);
// do you logic
return new Json(new { success=false, message="", errors=getHtmlContent(ModelState.Values.SelectMany(v => v.Errors).ToList(), "ModelError"));
}
This will do what you want to do.
Note: getHtmlContent method is just generating an error message to be displayed on page. Nothing so special. I may share it if required.
Your question is not very clear.
But as far as I could understand, the answer is most likely yes. You can update anything you want depending on the user input.
if(pass != true)
{
ViewData["Message'] = "Hey your login failed!"; Return View("Login")
}
On ViewPage
<form action="/tralala/Account/Login" method="post">
<input name="name" />Name<br />
<input name="password" type="password" />Password<br />
<button>Login</button>
<div style="color: red"><%=ViewData["Message"] %><div>
</form>