Update web api record with knockout.js - api

I have this method in controller:
// PUT: api/Books/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutBook(int id, Book book)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != book.Id)
{
return BadRequest();
}
db.Entry(book).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!BookExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
I have this method in Knockout.js
self.PutBook = function (item, book) {
ajaxHelper(booksUri + item.Id, 'PUT').done(function (item) {
self.books.put(item, book);
});
}
I want to update record with values that are entered in frontend input fields. What is missing in knockout.js? I'm not able to solve it.

From the javscript above, you should have used different variable name inside done because your action controller doesn't return item and you want to get the item object.
self.PutBook = function (item, book) {
ajaxHelper(booksUri + item.Id, 'PUT').done(function (result) {
self.books.put(item, book);
});
}

Related

Asp.net core api I can't enter more than one data on the same line

I have 3 tables, customer table has one to many relation with the other tables
a customer needs to add more than one address and phone number. With HTTPGET, I can pull data as follows, but I cannot perform crud operations.
enter image description here
GET:
[HttpGet("{id}")]
public async Task<ActionResult<Customer>> GetCustomer(int id)
{
var customers = _context.Customers
.Include(customer => customer.Adresses)
.Include(customer=> customer.Phones)
.Where(customer => customer.CId == id)
.FirstOrDefault();
if (customers == null)
{
return NotFound();
}
return customers;
}
POST:
[HttpPost]
public async Task<ActionResult<Customer>> PostCustomer(Customer customer)
{
_context.Customers.Add(customer);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (CustomerExists(customer.CId))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtAction("GetCustomer", new { id = customer.CId }, customer);
}
I can't enter more than one data on the same line
I want to receive customer information (how many addresses and phone numbers) at the same time as a record, I don't know how to do this.

When adding a new dynamic row with partial views, all rows cleared after deleting one

When the user adds an item to a list everything works fine until you delete an entry. The row gets deleted but once you add a new row, all rows are deleted with the new row added. The issue is that once you delete a row and add a new one it loads from the database, if you haven't saved the order yet everything entered is lost.
Is there a way to delete, then add, without saving the order every time you delete an item?
Js delete function
function del(e, id) {
e.currentTarget.parentElement.parentElement.remove()
if (id === 0) {
var row = $(this).closest(".tablerow0");
row.remove();
} else {
$.ajax({
url: '/Business/Order/DeleteOrderItem',
data: {
id: id
},
contentType: 'application/json',
success: function (data) {
},
error: function (e) {
console.log(e)
}
})
}
}
HTML
<div id="orderItemsContainer" style="width: 100%;float: left;">
#Html.EditorFor(model => model.Items)
</div>
Add Item
//Add new item
$(document).on('click', '#btnAdd', 'click', function (e) {
$.ajax({
async: true,
data: $('#forming').serialize(),
type: "POST",
url: '/Business/Order/AddOrderItem',
success: function (partialView) {
console.log("partialView: " + partialView);
$('#orderItemsContainer').html(partialView);
}
});
});
Html delete button
<button type="button" tabindex="-1" class="btntext-danger font-weight-bold clear-item" title="Remove" asp-action="DeleteOrderItem" asp-route-id="#Model.Id" asp-area="Business"
onClick="$(this).closest('.tablerow0').remove(); Update(); del(event, #Model.Id);showHideBtn()">
Controller
public IActionResult DeleteOrderItem(int id, [Bind("Items")] Order order)
{
if (id == 0)
{
return PartialView("Item", order);
}
var itemToDelete = _db.Items.Find(id);
_db.Remove(itemToDelete);
_db.SaveChanges();
return Json(itemToDelete);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddOrderItem([Bind("Items")] Order order)
{
order.Items.Add(new Item());
return PartialView("Item", order);
}
public IActionResult DeleteOrderItem(int id, [Bind("Items")] Order order)
{
if (id == 0)
{
return PartialView("Item", order);
}
var itemToDelete = _db.Items.Find(id);
_db.Remove(itemToDelete);
_db.SaveChanges();
return Json(itemToDelete);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddOrderItem([Bind("Items")] Order order)
{
order.Items.Add(new Item());
return PartialView("Item", order);
}
Check the above code, when add items, the items are not inserted into the database, but when you delete items, it will delete items from the database. So, the issue might relate that.
You could refer the comment to modify your code:
public IActionResult DeleteOrderItem(int id, [Bind("Items")] Order order)
{
if (id == 0)
{
return PartialView("Item", order);
}
//1. delete items from database.
var itemToDelete = _db.Items.Find(id);
_db.Remove(itemToDelete);
_db.SaveChanges();
//2. query database get the latest items:
var result = _db.Items.ToList();
//then return the items to the main page and display them
return Json(result);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddOrderItem([Bind("Items")] Order order)
{
//1. insert the items into database.
//2. query the database, get the latest items.
//3. add a new Item instance, to let use enter the new value.
order.Items.Add(new Item());
return PartialView("Item", order);
}

PUT request to API is setting values to NULL

I have this .Net Core API controller below that does a PUT request.
The table affected in Sql Server, looks like this:
carID (varchar(15), NULL)
optionID (varchar(15), NOT NULL)
optionDescription (varchar(255), NULL)
optionType (varchar(50), NULL)
factoryID (varchar(15), NULL)
In testing, I am sending along the properties I want changed like this in my PUT API call:
{
" optionID": "633fr",
"optionDescription": "Full Tech Package A"
}
It does update the entry in the database, but it's also setting all the values not sent in the PUT call to NULL. So while it does update optionDescription, it is setting all the other values to NULL except optionID.
How do I stop it from setting the other values?
thanks!
Here is the controller:
// PUT: api/CarOptions/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCarOptions(Guid id, CarOptions carOptions)
{
if (id != carOptions.OptionId)
{
return BadRequest();
}
_context.Entry(carOptions).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CarOptionsExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
According to your description, I suggest you could try to attach the model firstly and then set the specific property IsModified to true.
This will only update specific fields instead of updating whole model.
More details, you could refer to below example:
// PUT: api/CarOptions/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCarOptions(Guid id, CarOptions carOptions)
{
_context.Documents.Attach(carOptions);
_context.Entry(carOptions).Property(x => x.optionDescription).IsModified = true;
_context.SaveChanges();
return NoContent();
}

Phalcon keep a model persistant in all the controllers?

my website application is mostly model around a User Model which has all the key data that needed for most of the times.
Once the user is logged into the website I would like to keep it as a persistent variable across all the controllers. How do i achieve this as i cannot use session to hold a class object of Type Model.
My application is based on phalcon. However any suggestions are welcome.
I suggest you to write a simple class for user authentication & other user data manipulation, i wrote this Component and using in my project :
use Phalcon\Mvc\User\Component;
class Auth extends Component {
public function login($credentials) {
if(!isset($credentials['email'],$credentials['password'])) {
return FALSE;
}
if($this->isAuthorized()) {
return true;
}
$user = Users::findFirstByEmail($credentials['email']);
if($user == false) {
//block user for seconds
return false;
}
if($this->security->checkHash($credentials['password'],$user->password) && $user->status == 1) {
$this->_saveSuccessLogin($user);
$this->_setUserLoginSession($user);
return true;
} else {
return false;
}
}
public function isAuthorized() {
return $this->session->has('auth');
}
public function logout() {
$this->session->remove('auth');
return true;
}
public function user($key = null) {
if(!$this->isAuthorized()) {
return null;
}
if(is_null($key)) {
return $this->session->get('auth');
} else {
$user = $this->session->get('auth');
return array_key_exists($key, $user) ? $user[$key] : null;
}
}
private function _saveSuccessLogin(Users $user){
$userLogin = new UserLogins();
$userLogin->user_id = $user->id;
$userLogin->ip = $this->request->getClientAddress();
$userLogin->user_agent = $this->request->getUserAgent();
$userLogin->dns = gethostbyaddr($userLogin->ip);
if(!$userLogin->save()) {
return false;
}
return true;
}
private function _setUserLoginSession(Users $user) {
if(!$user) {
return false;
}
$this->session->set('auth',array(
'id' => $user->id,
'firstname' => $user->firstname,
'lastname' => $user->lastname,
'email' => $user->email,
'role_id' => $user->role_id
));
return true;
}
}
And in my services.php added into DI with this code :
$di->setShared('auth', function () {
return new Auth();
});
So when i want to get user info i use this :
$this->auth->user('email')
Also you can add more functionality to this component & modify it.
I hope that's useful for You.
You can use memcached and save it as key => value:
userId => serialized User model

MVC4 add overload to a method

As many of you know MVC4 has some great new features, I am struggling with the ContextDependentView trying to add an overload to it. I get an error saying no overload method for ContextDependentView takes 1 argument . My original code that was working was this
// This worked fine
return View(new ModelSample { getInfo= info, Retrieving= Retrieve })
// This is now what I have tried to do that doesn't work
return ContextDependentView(new ModelSample { getInfo= info, Retrieving= Retrieve })
//This is the method for ContextDependentView()
private ActionResult ContextDependentView()
{
string actionName = ControllerContext.RouteData.GetRequiredString("action");
if (Request.QueryString["content"] != null)
{
ViewBag.FormAction = "Json" + actionName;
return PartialView();
}
else
{
ViewBag.FormAction = actionName;
return View();
}
}
I obviously see that there are no overloads but how can I add an overload to the ContextDependentView method to accept my model like return View()..thanks
Add this overload to your controller:
private ActionResult ContextDependentView(SampleModel model)
{
string actionName = ControllerContext.RouteData.GetRequiredString("action");
if (Request.QueryString["content"] != null)
{
ViewBag.FormAction = "Json" + actionName;
return PartialView();
}
else
{
ViewBag.FormAction = actionName;
return View();
}
}
That should work...