Initiating DELETE request batman.js and rails 3 from index view - ruby-on-rails-3

I am creating a rails 3 app using batman.js for the front end. I am able to submit a successful delete request when I'm in the show.html view of an individual record. But when I am in the index.html view, the same pattern is not triggering the delete method. I am guessing there's a little magic occurring when Batman.js triggers a delete request which I do not understand. Probably something to do with the scope of the venue variable in the index.html view. I'll show my code for the controller and the two views in question. If you need something else, please ask.
/app/assets/javascripts/controllers/venues_controller.js.coffee
class Plansandpictures.VenuesController extends Batman.Controller
routingKey: 'venues'
index: (params) ->
#set 'newVenue', new Plansandpictures.Venue
Plansandpictures.Venue.load (err, venues) =>
#set 'venues', Plansandpictures.Venue.get('loaded')
show: (params) ->
Plansandpictures.Venue.find parseInt(params.id, 10), (err,result) =>
throw err if err
#set 'venue', result
#render source: 'venues/show'
create: (params) ->
#newVenue.save (err, venue) =>
if !err
#set 'newVenue', new Plansandpictures.Venue
Plansandpictures.Venue.get('loaded').add(venue)
update: (params) ->
destroy: (params) ->
#get('venue').destroy (err) =>
if err
throw err unless err instanceof Batman.ErrorsSet
else
Plansandpictures.flashSuccess "Removed successfully!"
#redirect '/venues'
/app/assets/javascripts/views/venues/show.html
<h4 data-bind="venue.name"></h4>
<h6>Description</h6>
<p data-bind="venue.description"></p>
<h6>Address</h6>
<p data-bind="venue.address"></p>
<h6>City</h6>
<p data-bind="venue.city"></p>
<h6>State</h6>
<p data-bind="venue.state"></p>
<a data-event-click="controllers.venues.destroy | withArguments venue">delete</a>
/app/assets/javascripts/views/venues/index.html
<h2>Venues</h2>
<table>
<thead>
<th>Name</th>
<th>Description</th>
<th>Address</th>
<th>City</th>
<th>State</th>
</thead>
<tbody>
<tr data-foreach-venue="venues">
<td data-bind="venue.name"></td>
<td data-bind="venue.description"></td>
<td data-bind="venue.address"></td>
<td data-bind="venue.city"></td>
<td data-bind="venue.state"></td>
<td><a data-route="routes.venues[venue]">show</a></td>
<td><a data-event-click="controllers.venues.destroy | withArguments venue">delete</a></td>
</tr>
</tbody>
</table>
<h3>Add a Venue</h3>
<form data-formfor-venue="controllers.venues.newVenue" data-event-submit="controllers.venues.create">
<input class="new-item" placeholder="Name" data-bind="venue.name" />
<input class="new-item" placeholder="Description" data-bind="venue.description" />
<input class="new-item" placeholder="Address" data-bind="venue.address" />
<input class="new-item" placeholder="City" data-bind="venue.city" />
<input class="new-item" placeholder="State" data-bind="venue.state" />
<input class="new-item" type="number" placeholder="1" data-bind="venue.user_id" />
<input type="submit" value="Add Venue" />
</form>

Your controller assumes it can fetch the venue via #get('venue'), but that's not necessarily set on the index view. So change:
destroy: (params) ->
#get('venue').destroy (err) =>
to:
destroy: (venue) ->
venue.destroy (err) =>
And this ought to work from both contexts.

Related

Complex DataBinding in Razor

Hi (I'm just a beginner), I have a cshtml view page in razor that I'm loading two separate queries in the page with one ID for the main part of the page and a bulkID for the detail page so one Id can have multiple bulkId's.
My View Looks like the following (Which is a grid) with data.
<thead>
#foreach (var item in Model.tblAllTransactionsWithDetail)
{
<tr>
<th class="noExport">Select</th>
<th class="noExport">Edit</th>
<th> #Html.LabelFor(modelItem => item.MemberNumber, "Member Number") </th>
<th> #Html.LabelFor(modelItem => item.EmployeeSSN, "Employee SSN") </th>
<th> #Html.LabelFor(modelItem => item.DependentSSN, "Dependent SSN") </th>
<th> #Html.LabelFor(modelItem => item.LastName, "Last Name") </th>
<th> #Html.LabelFor(modelItem => item.FirstName, "First Name") </th>
<th> #Html.LabelFor(modelItem => item.MiddleInitial, "Middle Initial") </th>
<th> #Html.LabelFor(modelItem => item.platform, "Platform") </th>
<th> #Html.LabelFor(modelItem => item.DateOfBirth, "Date of Birth")</th>
</tr>
}
</thead>
<tbody>
**#for (var i=0; i < Model.tblAllTransactionsWithDetail.Count; i++)
{**
<tr>
<td class="noExport">
<input id="checkbox" class="span" type="checkbox" name="" value="" />
<!-- use a hidden input field to just transfer data -->
#*<input type="hidden" asp-for="" value="#ViewBag.internalID" />*#
</td>
<td class="noExport">
<input type="hidden" value="SubmissionDetails" asp-for="#Model.url" />
<a asp-page="/EditDetails" asp-route-id="#Model.internalID">Edit</a>
</td>
#*<label for="colFormLabelLg" asp-for="tblAllTransactionsWithDetails.MemberNumber"></label>
#Html.DisplayFor(model => model.tblAllTransactionsWithDetail.MemberNumber)*#
<td>#Html.DisplayFor(model => model.tblAllTransactionsWithDetail.MemberNumber)</td>
<td>#Html.DisplayFor(model => model.EmployeeSSN)</td>
<td>#Html.DisplayFor(modelItem => item.DependentSSN)</td>
<td>#Html.DisplayFor(modelItem => item.LastName)</td>
<td>#Html.DisplayFor(modelItem => item.FirstName)</td>
<td>#Html.DisplayFor(modelItem => item.MiddleInitial)</td>
<td>#Html.DisplayFor(modelItem => item.platform)</td>
<td>#Html.DisplayFor(modelItem => item.DateOfBirth)</td>
</tr>
}
</tbody>
</table>
When I post the data It's always null values and one record. It should bring back 4 records.
public async Task<IActionResult> OnPostResubmitAsync(int? bulkID, IList<tblAllTransactionsWithDetails> tblAllTransactionsWithDetailbyBulkID)
{
//tblAllTransactionsWithDetailbyBulkID = await _db.tblAllTransactionsWithDetails.Where(d => d.bulkID == bulkID).ToListAsync();
var tbldetailsList = new List<tblAllTransactionsWithDetails>();
//tblAllTransactionsWithDetails details = new tblAllTransactionsWithDetails();
tblAllTransactionsWithDetails details = new tblAllTransactionsWithDetails()
{
};
tbldetailsList.Add(details);
// _db.AddRange(details);
// _db.SaveChanges();
if (ModelState.IsValid)
{
}
return Page();
}
Called from Resubmit Selected Lines button:
<div id="buttonContainer">
<div id="buttonLeft">
<p>
<label style="margin-right:100px;">Total Records Selected:</label><span style="margin-right:25px;">0</span>
<button style="margin-right:50px;" type="submit" class="btn-btn-primary" asp-page-handler="Search">Back to Search</button>
<button style="margin-right:50px;" id="resubmitEditedLines" class="btn btn-primary" type="submit" value="Resbumit Edited Lines" asp-page-handler="Resubmit">Resubmit Selected Lines</button>
<button style="margin-right:50px;" type="submit" class="btn btn-primary" onclick="$('#deleteModal').modal()" asp-page-handler="Delete">Delete Selected</button>
</div>
</div>
Problem1: I don't know to get the values to display in the model once it passes the values right now they are all null
Problem2: How do I refer the value if I use a for loop as above?
I'm using .Net Core Enity framework. I tried both methods above, but I'm not sure how to set the hiddenfor / displayfor values so that they save on post.
If you want to pass Model.tblAllTransactionsWithDetail to OnPostResubmitAsync,try to use hidden inputs like this:
<form method="post" asp-page-handler="Resubmit">
#for (var i = 0; i < #Model.tblAllTransactionsWithDetail.Count(); i++)
{
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].FirstName" name="tblAllTransactionsWithDetailbyBulkID[#i].FirstName" />
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].LastName" name="tblAllTransactionsWithDetailbyBulkID[#i].LastName" />
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].MemberNumber" name="tblAllTransactionsWithDetailbyBulkID[#i].MemberNumber" />
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].EmployeeSSN" name="tblAllTransactionsWithDetailbyBulkID[#i].EmployeeSSN" />
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].DependentSSN" name="tblAllTransactionsWithDetailbyBulkID[#i].DependentSSN" />
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].MiddleInitial" name="tblAllTransactionsWithDetailbyBulkID[#i].MiddleInitial" />
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].platform" name="tblAllTransactionsWithDetailbyBulkID[#i].platform" />
<input hidden asp-for="#Model.tblAllTransactionsWithDetail[#i].DateOfBirth" name="tblAllTransactionsWithDetailbyBulkID[#i].DateOfBirth" />
}
<button style="margin-right:50px;" id="resubmitEditedLines" class="btn btn-primary" type="submit" value="Resbumit Edited Lines">Resubmit Selected Lines</button>
</form>

vue.js does not correctly rerender compared to the vue instance object

I have a small issue with my vue template. The code is the following :
<template>
<div class="panel panel-default"
v-bind:id="'panel_'+noeud.id">
<div class="panel-heading">{{noeud.name}}</div>
<div class="panel-body">
<table class="table">
<thead>
<tr>
<th>Noeud</th>
<th>Poid</th>
</tr>
</thead>
<tbody>
<tr
v-for="noeud_poids in weightSorted"
v-if="noeud_poids.macro_zonning_noeud_id_2 != noeud.id"
is="macrozonningproximitenoeudpoids"
:noeud_poids="noeud_poids"
:noeud="noeud"
:noeuds="noeuds"
:delete_callback="delete_final"
:change_callback="update_line">
</tr>
<tr>
<td>
<select v-model="new_noeud">
<option value=""></option>
<option v-for="one_noeud in noeuds "
v-bind:value="one_noeud.id">{{one_noeud.name}}</option>
</select>
</td>
<td>
<input type="text" v-model="new_weight">
</td>
<td>
<input type="button" class="btn btn-primary" #click="addNoeudProximite" value="Ajouter"/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
export default {
props: ['pnoeud', 'pnoeuds'],
data: function(){
return {
points: 0,
points_restants: 100,
new_weight:0,
new_noeud:0,
noeud:this.pnoeud,
noeuds:this.pnoeuds,
weightSorted:this.pnoeud.weightSorted
}
},
mounted() {
},
methods:{
delete_final(macro_zonning_noeud_id_2){
axios.delete("/macrozonning/proximite/",{
params:{
macro_zonning_noeud_id_2:macro_zonning_noeud_id_2,
macro_zonning_noeud_id_1:this.noeud.id
}
}).then((res) => {
Vue.delete(this.weightSorted, String(macro_zonning_noeud_id_2));
})
},
update_line(nb_points){
this.points_restants = this.points_restants - nb_points;
this.points = this.points + nb_points;
},
addNoeudProximite(){
axios.put('/macrozonning/proximite/', {
'macro_zonning_noeud_id_1': this.noeud.id,
'macro_zonning_noeud_id_2': this.new_noeud,
'weight': this.new_weight
}).then((res) => {
Vue.set(this.weightSorted, String(this.new_noeud), res.data);
});
}
}
}
</script>
When the function delete_final is executed on the last item of my list, the view is correctly rerendered as the last item of my list is removed. But when I try to remove the first item of my list then the view rerenders but the the last item has been removed. When I check the Vue object in devtools, it does not reflect the new view, but it reflects the action taken (my first item has been removed).
If you have any idea where this problem comes from it would be awesome.
Thanks a lot community
Use a key attribute on the element you are rendering with v-for so that vue can exactly identify VNodes when diffing the new list of nodes against the old list. See key attribute
<tr> v-for="noeud_poids in weightSorted" :key="noeud_poids.id" </tr>

ASP .NET Core: Editable Grid: Insert dropdown list

Objetive: I'm trying to construct a view where the records from a table (machines) can be updated in a grid, and that each atribute of each record has the option to be chosen from a dropdownlist.
This is my Get method:
public async Task<IActionResult> Test()
{
return View(await _context.Machines.Include(t => t.MachineTypes).Include(p => p.Suppliers).Include(s=>s.Stores).AsNoTracking().ToListAsync());
}
And this is the definition for the dropdown list:
private void PopulateMachineTypeDropDownListStore(object selectedStore = null)
{
var typequery = from k in _context.Stores
orderby k.StoreName
select k;
ViewBag.StoreID = new SelectList(typequery.AsNoTracking(), "StoreID", "StoreName", selectedStore);
}
Now, to the View:
Model:
#model IEnumerable<Application.Models.Machine>
Since I need all the registers. Then the table.
Header:
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.MchName)
</th>
<th>
#Html.DisplayNameFor(model => model.StoreID)
</th>
</tr>
</thead>
Body:
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.MchName)
</td>
<td>
<div class="form-group">
<label asp-for="StoreID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="StoreID" class="form-control" asp-items="ViewBag.StoreID">
<option value="">-- Seleccione Tienda --
</option>
</select>
<span asp-validation-for="StoreID" class="text-danger"></span>
</div>
</div>
</td>
</tr>
}
</tbody>
</table>
}
Question: I've read that is not best to use a div inside a td but it may work, altough there may be better options. Which would be the best practice?
Question: Well, this is a Test but I'm getting this error:
"'IEnumerable' does not contain a definition for 'StoreID' and no extension method 'StoreID' accepting a first argument of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference?)"
I can't track the error. For me it looks fine and I don't know why it can't read the StoreID. I wonder if it's for the "asp-for" inside the div. I don't know.
Any help is appreciated.
Thanks

How do you open a kendo drop down popup on page load?

I have several uses for kendo drop-downs in my application (DDL, ComboBox, etc.).
I want them to open up on page load, but Kendo's documentation doesn't indicate that is possible.
I am using the MVC server variables.
This is my view coding:
<script id="itemTemplate" type="text/x-kendo-template">
# var index=FullName.indexOf(" *****");
if (index > 0)
{
#
<span style="font-weight:bold;">
#: FullName.substring(0, index)#
</span>
#
} else {
#
<span style="font-weight:normal;">
#: FullName#
</span>
#
}
#
</script>
<table class="form-horizontal table-condensed" style="width:100%;">
<tr style="height:400px;">
<td style="width:40%;vertical-align:top;">
<h4 style="width:100%;text-align:center;">Available Members</h4>
<h4 style="width:100%;text-align:center;font-size:smaller;">Current Cancer Center Members are highlighted in Bold.</h4>
#(Html.Kendo()
.MultiSelect()
.Name("AvailableWGMembers")
.DataTextField("FullName")
.DataValueField("id")
.ItemTemplateId("itemTemplate")
.TagTemplateId("itemTemplate")
.BindTo((System.Collections.IEnumerable)ViewBag.AvailableWGMembers)
.AutoBind(true)
.Placeholder("Click here to select one or more members to add, ...")
.AutoClose(false)
.HtmlAttributes(new { style = "width:100%;", #class = "Roles" })
.Events(events => { events.Change("doRoles");})
.Value(new int[0])
.Height(650)
)
</td>
<td style="width:20%;text-align:center;vertical-align:top;">
<input id="btnAdd" type="submit" value="Select" class="btn btn-default" disabled="disabled" />
</td>
<td style="width:40%;vertical-align:top;">
<h4 style="width:100%;text-align:center;">#Model.WGTitle</h4>
<h4 style="width:100%;text-align:center;font-size:smaller;">Current Cancer Center Members are highlighted in Bold.</h4>
#(Html.Kendo()
.MultiSelect()
.Name("ExistingWGMembers")
.AutoBind(false)
.DataTextField("FullName")
.DataValueField("id")
.ItemTemplateId("itemTemplate")
.TagTemplateId("itemTemplate")
.BindTo((System.Collections.IEnumerable)ViewBag.ExistingWGMembers)
.Placeholder("Click here to select one or more members to remove, ...")
.AutoClose(true)
.HtmlAttributes(new { style = "width:100%;", #class = "UnusedRoles" })
.Events(events => { events.Change("doRoles"); })
.Value(new int[0])
.Height(650)
)
</td>
</tr>
</table>
I want the lists to both be open when the page loads, and I want to be able to use unobstrusive jQuery or javascript to control it if I have to.
Does anyone have any suggestions?
It took a little digging, but I finally figured out the answer. It was actually pretty simple.
The following should be added to the unobstrusive javascript code file:
function openPopup(e)
{
if (e.sender.list[0].childNodes['1'].childNodes['0'].childElementCount > 0) {
e.sender.popup.open();
}
}
You add the following code to your event listing:
.Events(events => { ...; events.DataBound("openPopup"); })
This can be done with any of the lists that have popups like Kendo DropDownList or ComboBox or MultiSelect.
I would check for the list length to make sure the list has members so you don't get an ugly empty list shown, but otherwise the result is actually pretty simple.
This answer is dependent upon the code example at: http://demos.telerik.com/aspnet-mvc/window/index
I took that example from the Index.cshtml version of their example and simply replaced the Content value of the # with your table template from the original question:
#(Html.Kendo().Window()
.Name("window")
.Title("Your modal popup with dropdown menus")
.Content(#<text>
<table class="form-horizontal table-condensed" style="width:100%;">
<tr style="height:400px;">
<td style="width:40%;vertical-align:top;">
<h4 style="width:100%;text-align:center;">Available Members</h4>
<h4 style="width:100%;text-align:center;font-size:smaller;">Current Cancer Center Members are highlighted in Bold.</h4>
#(Html.Kendo()
.MultiSelect()
.Name("AvailableWGMembers")
.DataTextField("FullName")
.DataValueField("id")
.ItemTemplateId("itemTemplate")
.TagTemplateId("itemTemplate")
.BindTo((System.Collections.IEnumerable)ViewBag.AvailableWGMembers)
.AutoBind(true)
.Placeholder("Click here to select one or more members to add, ...")
.AutoClose(false)
.HtmlAttributes(new { style = "width:100%;", #class = "Roles" })
.Events(events => { events.Change("doRoles");})
.Value(new int[0])
.Height(650)
)
</td>
<td style="width:20%;text-align:center;vertical-align:top;">
<input id="btnAdd" type="submit" value="Select" class="btn btn-default" disabled="disabled" />
</td>
<td style="width:40%;vertical-align:top;">
<h4 style="width:100%;text-align:center;">#Model.WGTitle</h4>
<h4 style="width:100%;text-align:center;font-size:smaller;">Current Cancer Center Members are highlighted in Bold.</h4>
#(Html.Kendo()
.MultiSelect()
.Name("ExistingWGMembers")
.AutoBind(false)
.DataTextField("FullName")
.DataValueField("id")
.ItemTemplateId("itemTemplate")
.TagTemplateId("itemTemplate")
.BindTo((System.Collections.IEnumerable)ViewBag.ExistingWGMembers)
.Placeholder("Click here to select one or more members to remove, ...")
.AutoClose(true)
.HtmlAttributes(new { style = "width:100%;", #class = "UnusedRoles" })
.Events(events => { events.Change("doRoles"); })
.Value(new int[0])
.Height(650)
)
</td>
</tr>
</table>
</text>)
.Draggable()
.Resizable()
.Width(600)
.Actions(actions => actions.Pin().Minimize().Maximize().Close())
.Events(ev => ev.Close("onClose"))
)
I hope this helps!

How do I include html in C# block and C# in html block in the following View?

I have my view here and it throws errors, either there is missing {} block or an "eternal components throws and exception" when I remove those if/else block along with #: the code works just like before so how do I include html code in a C# block and C# code in html block in the following view:
#model IEnumerable<ecomm2.Models.HomeSearchResultsViewModel>
#{
if (Model.Count < 1)
{
#:<p style="color:red">Item not found</p>
}
else
{
#:<table style="background-color:#f7f7f7;width:100%; border:0px solid black;">
foreach (var item in Model) {
#:<tr style="border:1px solid #bbb9b9;">
#: <td style="width:177px;">
#: <img src="~/Content/images/meter.jpeg" alt="Alternate Text" style="height:177px;width:177px;padding:10px;"/>
#:</td>
#:<td style="width:100%;padding-left:2px;float:left;padding-top:20px;border:0px solid black;font-size:medium">
<span>
#Html.ActionLink(item.ProductLineName, "GetProductDetails", "Product", new { id = item.Id }, new { }) <br />
#: </span>
#:<span style="font-size:small">By #Html.ActionLink(item.BrandName, "GetProductByBrandName", new { id=item.BrandName})</span><br />
#:<span style="font-size:x-small">
#Html.ActionLink(item.CategoryName, "GetProductsByCategoryName", new { id=item.CategoryName}) | Stock Count: #Html.DisplayFor(modelItem => item.StockCount)
</span><br />
#using(Html.BeginForm("AddToCart", "Cart", new { id=item.Id}))
{
<fieldset>
<input type="submit" name="name" value="Add to Cart" class="btn btn-default"/>
</fieldset>
}
</td>
<td style="width:20%;color:#00b02f;font-weight:bold;padding-top:20px;float:none;padding-left:20px;">
LKR: #Html.DisplayFor(modelItem => item.ListPrice)
</td>
</tr>
}
#:</table>
}
}
Here is the original code that threw the error
External component has thrown an exception.
Here is the original code
#model IEnumerable<ecomm2.Models.HomeSearchResultsViewModel>
#if (Model.Count < 1)
{
<p style="color:red">Item not found</p>
}
else
{
<table style="background-color:#f7f7f7;width:100%; border:0px solid black;">
#foreach (var item in Model) {
<tr style="border:1px solid #bbb9b9;">
<td style="width:177px;">
<img src="~/Content/images/meter.jpeg" alt="Alternate Text" style="height:177px;width:177px;padding:10px;"/>
</td>
<td style="width:100%;padding-left:2px;float:left;padding-top:20px;border:0px solid black;font-size:medium">
<span>
#Html.ActionLink(item.ProductLineName, "GetProductDetails", "Product", new { id = item.Id }, new { }) <br />
</span>
<span style="font-size:small">By #Html.ActionLink(item.BrandName, "GetProductByBrandName", new { id=item.BrandName})</span><br />
<span style="font-size:x-small">
#Html.ActionLink(item.CategoryName, "GetProductsByCategoryName", new { id=item.CategoryName}) | Stock Count: #Html.DisplayFor(modelItem => item.StockCount)
</span><br />
#using(Html.BeginForm("AddToCart", "Cart", new { id=item.Id}))
{
<fieldset>
<input type="submit" name="name" value="Add to Cart" class="btn btn-default"/>
</fieldset>
}
</td>
<td style="width:20%;color:#00b02f;font-weight:bold;padding-top:20px;float:none;padding-left:20px;">
LKR: #Html.DisplayFor(modelItem => item.ListPrice)
</td>
</tr>
}
</table>
}
In the Index view it calls the partial page "_SearchResultList" here is the video that shows all
None of your #: code is necessary. The reason you get the exception is that IEnumerable<T> does not have a property Count so your if block throws an exception. Change you code to
if (Model.Count() < 1)
of better, use
if (Model.Any())
and swap the code in the if and else blocks