I have a view with a GridMVC and two buttons, in which I'm displaying several parameters of the model, and the buttons Edit or Delete the item in that row.
#Html.Grid(Model).Named("eventsGrid").Columns(columns =>
{
columns.Add(model => model.Summary)
.Titled("Nombre");
columns.Add(model => model.Description)
.Titled("Descripción");
columns.Add(model => model.StartDate)
.Titled("Fecha Inicio");
columns.Add(model => model.EndDate)
.Titled("Fecha Fin");
columns.Add()
.Sanitized(false)
.Encoded(false)
.SetWidth(30)
.RenderValueAs(model => (#Html.ActionLink("Editar", "EditEvent", "Home", new { eventId = model.EventID, calendarId = model.CalendarID }, new { #class = "btn btn-default" }).ToHtmlString()));
columns.Add()
.Sanitized(false)
.Encoded(false)
.SetWidth(30)
.RenderValueAs(model => (#Html.ActionLink("Borrar", "Delete", "Home", new { eventId = model.EventID, calendarId = model.CalendarID }, new {#class = "btn btn-default"}).ToHtmlString()));
What I want to do is that when I click the Delete button, an alert appears to confirm that you want to delete the item, so I made this function in a .js file:
function confirmDelete(EventID, CalendarID) {
if (confirm('¿Desea borrar este evento?'))
{
$.ajax({
url: '#Url.Action("Delete","Home")',
data: { eventId: EventID, calendarId: CalendarID }
})
} else {
// Do nothing!
}
}
I changed it to look like this:
.RenderValueAs(model => #<button onclick="confirmDelete('model.EventID','model.CalendarID')" class='btn btn-default'>Borrar</button>);
but this makes the values in the function literally model.EventID and model.CalendarID, and I can't use #model.EventID as it's already inside an #. I also tried with an answer from How to pass a model field to a Javascript function in a view?:
.RenderValueAs(model => #<button onclick="confirmDelete('" + model.EventID "')" class='btn btn-default'>Borrar</button>);
But this doesn't even call the function.
Which is the correct form to write the models parameters to make it work?
You can use an HtmlString:
.RenderValueAs(model => new HtmlString("<button onclick='confirmDelete(" + model.EventID + ", " + model.CalendarID + ")' class='btn btn-default'>Borrar</button>"));
Related
I have a couple of drop down lists... The first of which has an onchange event that calls a Javascript funcction:
#for (int i = 0; i < Model.things.Count; i++)
{
<tr>
<td>
#Html.DropDownListFor(m => m.Category[i].ID, ViewBag.Category as SelectList, "Please select a Category", new { #class = "class1", onchange = "Changed(this)" })
</td>
<td>
#Html.DropDownListFor(m => m.SubCategory[i].ID, Enumerable.Empty<SelectListItem>(), "Please select a Sub Category", new { #class = "class2" })
</td>
</tr>
}
Within this function I am making an ajax call to a controller method that returns a SelectList:
function TrackerChanged(val) {
var id = val.value;
$j.ajax({
url: appRoot + 'Controller/Method',
type: 'post',
data: { 'id': id},
success: function (results) {
if (results) {
**** POPULATE SECOND DROPDOWN ABOVE ***
}
else {
alert("Error updating comment");
}
},
failure: function () {
alert("Error updating comment");
}
});
}
The Controller Method returns a SelectList:
public SelectList Method(id categoryID)
{
IEnumerable<SelectListItem> select = null;
// Populate the IEnumerable with SubCategory results to show in the second Drop Down
return new SelectList(select, "Value", "Text");
}
but as you may notice from the comment in my ajax success chunk - I do not know how I would bind my new results back to the controller.
Please can someone help. I have looked for some examples and nothing seems to be working for me.
First of, I'm very new to NativeScript. I followed a tutorial for a ToDo list found here https://x-team.com/blog/build-simple-todo-list-mobile-application-nativescript/, and as a little exercise for myself I wanted to add a remove function for the tasks inside a list.
Here's my code:
Tasks.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onNavigatingTo">
<Page.actionBar>
<ActionBar title="Tasks">
<ActionBar.actionItems>
<ActionItem text="New" tap="{{ insert }}" ios.position="right" />
<ActionItem text="Delete" tap="{{ delete }}" ios.position="right" />
</ActionBar.actionItems>
</ActionBar>
</Page.actionBar>
<ListView items="{{ tasks }}"></ListView>
tasks-view-model.js
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var Sqlite = require("nativescript-sqlite");
var Dialogs = require("ui/dialogs");
function createViewModel(database, listId) {
var viewModel = new Observable();
viewModel.tasks = new ObservableArray([]);
viewModel.listId = listId;
viewModel.insert = function() {
Dialogs.prompt("Task Name", "").then(result => {
database.execSQL("INSERT INTO tasks (list_id, task_name) VALUES (?, ?)", [this.listId, result.text]).then(id => {
var _string = "ID: " + id + ", " + result.text;
this.tasks.push(_string);
}, error => {
console.log("INSERT ERROR", error);
});
});
}
viewModel.select = function() {
this.tasks = new ObservableArray([]);
database.all("SELECT id, task_name FROM tasks WHERE list_id = ?", [this.listId]).then(rows => {
for(var row in rows) {
var _id = rows[row][0];
var _item = rows[row][1];
var _string = "ID: " + _id + ", " + _item;
this.tasks.push(_string);
}
}, error => {
console.log("SELECT ERROR", error);
});
}
viewModel.delete = function() {
Dialogs.prompt("Task ID", "").then(result => {
database.execSQL("DELETE FROM tasks WHERE id = ?", [result.text]).then(id => {
Dialogs.prompt(id);
}, error => {
console.log("DELETE ERROR", error);
});
});
}
viewModel.select();
return viewModel;
}
exports.createViewModel = createViewModel;
The actual deleting of the item when passing its ID works fine. However the UI doesn't show this change without me manually refreshing it, and I cannot figure out why. In case it matters, I'm running this on an Android emulator.
Thanks in advance for your help.
Inside your delete function you also need to remove the item from the ObservableArray.
viewModel.delete = function() {
Dialogs.prompt("Task ID", "").then(result => {
database.execSQL("DELETE FROM tasks WHERE id = ?", [result.text]).then(id => {
Dialogs.prompt(id);
/// remove the item from the observable array.
this.tasks.splice(INDEX_OF_THE_ITEM_DELETED,1);
}, error => {
console.log("DELETE ERROR", error);
});
});
}
You may want to consider changing the ObservableArray of tasks from an array of strings to an array of Objects with an id property and value property. So it's easier to determine the index of the item you want to remove. If not you will have to rebuild value that is pushed into the array to find the index.
I have a partial view which is used to show a checkbox in a column of table in razor. When I click on any checkbox in the table its posting back to controller with Id of first row and not the Id of row in which the check-box is contained. The javascript function to post ajax request is "SaveChanges" as given below.
The hidden field "RecurrenceScheduleId" is the primary key id.
Am I doing something wrong here?
- Following are my view & controller action:
#model SMRDS.Model.RecurrenceSchedule
#using (Ajax.BeginForm("_LogOccurancePartial", "Schedule",
new AjaxOptions
{
UpdateTargetId = "tdOccurance",
HttpMethod = "post",
LoadingElementId = "btnProgress",
OnBegin = "dialogBegin",
OnSuccess = "updateSuccess",
OnFailure = "dialogFailure"
},
new { id = "frm-toggle" }))
{
#Html.HiddenFor(model => model.RecurrenceScheduleId)
#Html.CheckBoxFor(m => m.LogOccurences, new { #onclick ="SaveChanges(this)" })
}
<script>
function updateSuccess() {}
function dialogFailure() {}
function dialogComplete() {}
function dialogBegin() {}
function SaveChanges(checkboxInput) {
$.ajax({
type: 'POST',
url: '/Schedule/_LogOccurancePartial',
data: { newValue: checkboxInput.checked, id: $("#RecurrenceScheduleId").val() },
dataType: 'json',
success: function (response) {
//handle success
}
});
}
Controller Action :
public JsonResult _LogOccurancePartial(bool newValue,int id)
{
var result = BLL.Service.RecurrenceSchedules.UpdateLogOccurence(id, newValue);
return Json(new { result = result }, JsonRequestBehavior.AllowGet);
}
Update
Following is the html rendered for hidden fields. At present I have only two rows with Ids "40" & "41".
<input data-val="true" id="RecurrenceScheduleId"
name="RecurrenceScheduleId" type="hidden" value="40">
<input data-val="true" id="RecurrenceScheduleId"
name="RecurrenceScheduleId" type="hidden" value="41">
It is your responsibility to maintain unique ids when you use the helpers.
If you had a model
public class ViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
And your view contains a collection you can use a for loop with an index to override the id with unique values.
#model List<ViewModel>
#for(int i = 0; i < Model.Count(); i++)
{
#Html.HiddenFor(m => Model[i].Id, htmlAttributes: new { id = "item" + item.Id })
}
But you can also adjust your click handler so you don't need to find a hidden input by id.
#Html.CheckBoxFor(m => m.LogOccurences,
new { #class="trigger", data_rsid=m.RecurrenceScheduleId })
<script>
$("body").on("click", ".trigger", function(e) {
var rsId = $(this).data("rsid");
var checked = $(this).prop("checked");
var data = { newValue: checked, id: rsId }
$.ajax({ ... });
});
</script>
I have a page in MVC, where i need to display the details of the records.
The records needed to be fetched from 2 tables for which i have Model separately.
Now, for this page needing both the models, I have created another model which have those 2 model referred.
[Please note, following nomenclature's are only for example purposes.]
public class CombinedModel
{
public Model1 objModel1 { get; set; }
public Model2 objModel2 { get; set; }
}
In the view [Details.cshtml], I have following code:
#model Application.Web.Models.CombinedModel
<div>
#Html.Label("Label text: ", htmlAttributes: new { #class = "control-label" })
#Html.DisplayFor(model => model.objModel1.Property1, new { htmlAttributes = new { #class = "form-control" } })
</div>
And a popup code
<div id="Modal">
<div>
#Html.Label("Popup label text:", htmlAttributes: new { #class = "control-label" })
#Html.DisplayFor(vmodel => vmodel.objModel2.Property2, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
The page loads with the data in from the first model successfully from controller action.
I needed Data in the popup code, only when user clicks on particular record, from where View will send ID and will display record for that particular ID from the second model.
In Controller:
public class ControllerNameController : Controller
{
[HttpGet]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
[ValidateInput(false)]
public ActionResult Details(int? Id, string strType, string strVersionID)
{
var Details1 = db.Table1.FirstOrDefault(rd => rd.SomeID == Id);
CombinedModel modelCombined = new CombinedModel();
Model1 objectM1 = new Model1();
objectM1.Property1 = Details1.Column1;
var VersionDetails = db.Table2.FirstOrDefault(rvd => rvd.somePrimaryKeyID == Convert.ToInt32(strVersionID));
if (VersionDetails != null)
{
Model2 objectM2 = new Model2();
objectM2.vCreatedOn = VersionDetails.Property2;
modelCombined.objModel2 = objectM2;
ViewBag.VersionID = VersionDetails.VersionID;
}
modelCombined.objModel1 = objectM1;
return View(rmodel);
}
}
The page landing URL is:
function JavascriptFunctionInParentView(IDToPass, strTypeToPass)
{
top.location.href = "#Url.Action("Details", "ControllerName")"
+ "?Id=" + IDToPass
+ "&strType='" + strTypeToPass + "'"
+ "&strVersionID='0'";
}
SO, when first time page loads, we have strVersionID as Zero. So, it will not enter in VersionDetails block and fill only Model1 data.
Now, when we are Details page, there is a grid, from which, I need to populate the version details in the popup, for which I have working code as following:
function recordDoubleClickRuleVersion(args) {
top.location.href = "#Url.Action("Details", "ControllerName")"
+ "?Id=" + #Url.RequestContext.HttpContext.Request.QueryString["Id"]
+ "&strType=" + '#Url.RequestContext.HttpContext.Request.QueryString["strType"]'
+ "&strVersionID=" + args.data.VersionID;
}
// ....
$(function () {
if ('#(ViewBag.VersionID)' == "") {
$("#Modal").ejDialog("close");
}
if ('#(ViewBag.VersionID)' != "") {
$("#Modal").ejDialog(
{ enableModal: true, enableResize: false, close: "onDialogClose", width: "60%" });
$("#Modal").ejDialog("open");
}
})
My problem is, when i call this Version details popup, page postbacks and then data comes.. I know i have given #Url.Action to it so it is behaving like this way.
I needed it to be by complete Client-side code and I tried following code as well. It open's popup but doesn't fill value in it.
$.ajax({
type: "GET",
data: ({
"Id": #Url.RequestContext.HttpContext.Request.QueryString["Id"],
"strType": '#Url.RequestContext.HttpContext.Request.QueryString["strType"]',
"strVersionID": args.data.VersionID }),
url: '#Url.Action("RuleDetails", "Rules")',
})
.done(function (RuleVersionDetails) {
// 1. Set popup
$("#Modal").ejDialog(
{ enableModal: true, enableResize: false, close: "onDialogClose", width: "60%" });
// 2. Open popup
$("#Modal").ejDialog("open");
});
Can you please tell me the solution for this ?
You can change you Details() Action to return a Json object, and then fill the dialog with it.
$.ajax({
type: "GET",
data: ({
"Id": #Url.RequestContext.HttpContext.Request.QueryString["Id"],
"strType": '#Url.RequestContext.HttpContext.Request.QueryString["strType"]',
"strVersionID": args.data.VersionID }),
url: '#Url.Action("RuleDetails", "Rules")',
})
.done(function (jsonData) {
// **TODO: file dialog with properties of jsonData**
// 1. Set popup
$("#Modal").ejDialog(
{ enableModal: true, enableResize: false, close: "onDialogClose", width: "60%" });
// 2. Open popup
$("#Modal").ejDialog("open");
});
The best approach for your case is using bootstrap modal.Go here and check its documentation and how to config. If you aren't familiar with bootstrap or modal, it really worth to learn.
But remember when you want sent data to modal section, make it dynamic based on your item id in grid.
My Create view was like this:
#model ContactProject.Models.Activity.Activity
#{
ViewBag.Title = "Create";
IEnumerable<ContactProject.Models.Activity.Activity> activities = ViewBag.Activities;
}
<div class="editor-label">
#Html.Label("Project")
</div>
<div class="editor-field">
#Html.DropDownList("Projects", ViewBag.Project as SelectList,"----Project----", new { id = "ProjectsID" })
#Html.ValidationMessageFor(model => model.iProjectID)
</div>
<div class="editor-label">
#Html.Label("Title")
</div>
<div class="editor-field" id="TitlesDivID">
<select id="TitlesID" name="Titles"></select>
</div>
// other codes...
if (activities !=null){
// Display activities.
}
here is the code of my JS
$('#ProjectsID').change(function () {
var URL = 'TitleList';
$.getJSON(URL + '/' + $('#ProjectsID').val(), function (data) {
var items = '<option>Select a Title</option>';
$.each(data, function (i, title) {
items += "<option value='" + title.Value + "'>" + title.Text + "</option>";
if (items != null)
{
var addValue = $('#ProjectsID').val();
$.ajax
({
type: "POST",
url: "/Activity/getCreateActivities",
data: { projectID: addValue },
success: function (#ViewBag.Activities) {
}
})
}
})
basically I want to implement my function with this JS to display not only of title related to the project but also all the activities has the same project name.
That's why I'm writing "success: function (#ViewBag.Activities) in my jquery call back function."
here is the method in my controller:
public ActionResult getCreateActivities(string projectID)
{
int iProjectID = Int32.Parse(projectID);
ViewBag.Project = GetProjects();
var Activities = (from a in db.Activities
where a.iProjectID == iProjectID
select a).ToList();
ViewBag.Activities = Activities;
return View("Create");
}
but when I am using breakpoint to debug, there are #ViewBag.Activities returned with value and counts, but seems like didn't display on my screen, anyone has any thoughts on that? any contribute will be greatly appreciated.
Update:
<table>
#foreach (var item in Activities) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProjectID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project.ProjectName)
</td>
</tr>
If you set some values in ViewBag with an ajax request, you won't get it. The rite way to handle this is, simply return the data in JSON format and access it.
public ActionResult getCreateActivities(string projectID)
{
int iProjectID = Int32.Parse(projectID);
var Activities = (from a in db.Activities
where a.iProjectID == iProjectID
select a).ToList();
return Json(new { Projects : GetProjects(),
Activities : Activities } ,JsonRequestBehaviour.AllowGet);
}
The above will return a JSON representation of an anonymous object like this
{
"Projects": [ { "Id": 2 } ],
"Activities": [ { "id": 113,"Name": "My name" } ]
}
And in your ajax method's success callback, access it like
success(function(data){
// now you can acceess data.Projects and data.Activities
}