I have to refresh the items of two ListBox after a dropdownlist value change.
The data of the ListBoxes is in the ViewData and i call a action controller from jquery function, but the ViewData after the call have the same data.
Here is the code:
$(document).ready( function () {
$('#users').change(function () {
var selectedValue = $('#users').val();
$.post('#Url.Action("GruposUsuario", "Grupos")', { usersId: selectedValue }, function () {
var gruposAsig = JSON.parse('#Html.Raw(Json.Encode(ViewData["gruposAsignados"]))');
var gruposDisp = JSON.parse('#Html.Raw(Json.Encode(ViewData["gruposDisponibles"]))');
$('#gruposAsignados').empty();
$('#gruposAsignados').addItems(gruposAsig);
$('#gruposDisponibles').empty();
$('#gruposDisponibles').addItems(gruposDisp);
});
});
$.fn.addItems = function (grupos) {
return this.each(function () {
var list = this;
$.each(grupos, function (index, itemData) {
var option = new Option(itemData.Text, itemData.Value);
list.add(option);
});
});
};
});
And the Controller Code:
[HttpPost]
public ActionResult GruposUsuario(string usersId)
{
AllUsers();
GruposAsignados(int.Parse(usersId));
//GruposDispobibles(int.Parse(usersId));
return Json("Usuario");
}
void GruposAsignados(int usersId)
{
var grupos = new BL.Grupos().GruposAsignados(usersId);
List<SelectListItem> list = new List<SelectListItem>();
foreach (var grupo in grupos)
{
SelectListItem selectList = new SelectListItem()
{
Text = grupo.GroupName,
Value = grupo.GroupsId.ToString()
};
list.Add(selectList);
}
ViewData["gruposAsignados"] = list as IEnumerable<SelectListItem>;
}
How can i refesh the ViewDatas after the event?
Razor code is parsed on the server before it is sent to the view. Your use of #Html.Raw(...) assigns vales to gruposAsig and gruposDisp that are the initial values of the ViewData properties (inspect the source when you first render the page).
In any case you method GruposAsignados() only returns a string with the value "Usuario". If you want to return json data to update the options in two dropdownlists, then you controller method should be
[HttpGet] // its a GET
public ActionResult GruposUsuario(string usersId)
{
var gruposAsignados= new BL.Grupos().GruposAsignados(usersId).Select(g => new
{
ID = g.grupo.GroupsId;
Name = g.GroupName;
}
var gruposDisponibles = // another query
return Json(new { Asignados = gruposAsignados, Disponibles = gruposDisponibles, JsonRequestBehavior.AllowGet);
}
Then the script should be
var asignados = $('#gruposAsignados'); // cache it
var disponibles = $('#gruposDisponibles');
$.getJSON('#Url.Action("GruposUsuario", "Grupos")', { usersId: selectedValue }, function (response) {
if(response) {
asignados.empty();
// or asignados.empty().append($('</option>').val('').text('-Please select-'));
$.each(response.Asignados, function(index, item) {
asignados.append($('</option>').val(item.ID).text(item.Name));
});
disponibles.empty();
$.each(response.Disponibles, function(index, item) {
disponibles.append($('</option>').val(item.ID).text(item.Name));
});
}
});
Side note: There is no need to create IEnumerable<SelectListItem>. The browser has no knowledge of what a C# class is and you just returning extra unnecessary data (the values of the Selected, Group and Disabled properties) which are never used.
Related
I have list of objects in my MVC model as below.
#Html.EditorFor(model => model.LstEmploymentHistory)
<button id="btnAddHistory" data-bind="click: addHistory">Add one</button>
I need to bind this to Knockout observable array on load.
<script type="text/javascript">
//Data
var History = function () {
var self = this;
self.CompanyName = ko.observable();
self.Designation = ko.observable();
self.StartDate = ko.observable();
self.EndDate = ko.observable()
};
var viewModelEmploymentHistory = function () {
// Operations
var self = this;
self.historyList = ko.observableArray([new History()]); // Put one line in by default
self.addHistory = function () { self.historyList.push(new History()) }
self.removeHistory = function (history) {
self.historyList.remove(history)
}
self.educationList = ko.observableArray([new Education()]); // Put one line in by default
self.addEducation = function () { self.educationList.push(new Education()) };
self.removeEducation = function (education) {
self.educationList.remove(education)
}
};
//Data
var Education = function () {
var self = this;
self.Degree = ko.observable();
self.YearOfPassing = ko.observable();
self.Percentage = ko.observable();
self.Institute = ko.observable()
};
//var masterVM = (function () {
// this.viewModelEducationalDetails = new viewModelEducationalDetails(),
// this.viewModelEmploymentHistory = new viewModelEmploymentHistory();
//})();
//ko.applyBindings(masterVM)
ko.applyBindings(new viewModelEmploymentHistory());
// ko.applyBindings(new viewModelEducationalDetails(), document.getElementById("containerEducation"));
//ko.applyBindings(new viewModelEmploymentHistory(), document.getElementById("containerHistory"));
</script>
Can any one please help me with the way to bind the C# list to the observable array on page load.?
You will need to use a format that JavaScript understands, like JSON..
So in your controller you'll need to serialise the model into a JSON string
something like:
Model.JsonString = JsonConvert.SerializeObject(Model.LstEmploymentHistory);
You can then consume this in your JavaScript/MVC, several way to do this. The easiest is to simply write it to an input
#Html.HiddenFor(h => h.JsonString);
Then read it in your js:
var Json = document.getElementById('JsonString').value;
and then turn this back into an array:
var array = JSON.Parse(Json);
You then need to bind that into your observable. You've not actually explained how this is supposed to work so I'll leave this one to you...
If you bind in Razor then you can use the following:
var myModel = {
LstEmploymentHistory: #Html.Raw(Json.Encode(Model.LstEmploymentHistory))
};
This is driving me crazy... as part of another issue I've been working on ajax transfers to my mvc4 web app.
I've been working with this as an example: http://www.codeproject.com/Articles/692793/Introduction-to-Knockout-js-and-CRUD-Operations-in
The model is as follows:
public class ColorList
{
public int? ID;
public string ColorName;
}
The controller function is as follows:
[WebMethod]
public ColorList[] GetAssignedColors(string szUserRecID)
{
int Rec = Convert.ToInt32(szUserRecID);
var query = (from t in db.tblColors
join c in db.tblUser on t.fkColorID equals c.pkColorID
where t.fkRecID == Rec
select new ViewModels.ColorList()
{
ColorName = c.szColorName,
ID = t.ColorID
}).OrderBy(c => c.ColorName);
//var q = query.ToArray(); // if I break and view q, the array exists
return query.ToArray();
}
Not sure this matters but here's my Ajax method:
$.ajax({
type: "POST",
url: '#Url.Action("GetAssignedColors", "EditColors")',
data: { szUserRecID: RecID },
success: function (results) {
var colors = $.map(results.d, function (item) {
return new Color(item)
});
self.CurrentColors(colors);
},
error: function (err) {
alert(err.status + " : " + err.statusText);
}
})
if I watch fiddler the response my code provides is (in text view):
"MyApps.ViewModels.ColorList[]"
Not the array of colors as I am expecting.
Why is the function returning the variable name as an array instead of the array itself?
I've played around with this, but my ajax call doesn't seem to interpret the json response... However, the data shows in this instance but get a 200/ok with seemingly unusable data in my web page.
[HttpPost]
public JsonResult GetAssignedColors(string szUserRecID)
{
int Rec = Convert.ToInt32(szUserRecID);
var query = (from t in db.tblColors
join c in db.tblUser on t.fkColorID equals c.pkColorID
where t.fkRecID == Rec
select new ViewModels.ColorList()
{
ColorName = c.szColorName,
ID = t.ColorID
}).OrderBy(c => c.ColorName);
//var q = query.ToArray(); // if I break and view q, the array exists
return Json(query.ToArray(), JsonRequestBehavior.AllowGet);
}
Since formatting didn't work in the comments this is what worked; results didn't have the data necessary but "data" did.
success: function (data) {
var colors = $.map(data, function (item) {
return new Color(item)
});
The webpage I was working off of had:
success: function (result) {
var colors = $.map(result.d, function (item) {
return new Color(item)
});
The actual working method was:
success: function (data) {
var colors = $.map(data, function (item) {
return new Color(item)
});
I did not use the [webmethod] per Robert's wisdom and used the json response.
The final / working function was:
[HttpPost]
public JsonResult GetAssignedColors(string szUserRecID)
{
int Rec = Convert.ToInt32(szUserRecID);
var query = (from t in db.tblColors
join c in db.tblUser on t.fkColorID equals c.pkColorID
where t.fkRecID == Rec
select new ViewModels.ColorList()
{
ColorName = c.szColorName,
ID = t.ColorID
}).OrderBy(c => c.ColorName);
//var q = query.ToArray(); // if I break and view q, the array exists
return Json(query.ToArray());
}
Note the removal of JsonRequestBehavior.AllowGet
thanks Robert!
here is my code which is giving me above error
public ActionResult Edit(int id = 0)
{
KBS_Virtual_TrainingEntities db = new KBS_Virtual_TrainingEntities();
UsersContext ctx = new UsersContext();
UserProfile model = ctx.UserProfiles.Find(id);
List<CourseSubscription> user_Course_subscriptions = new List<CourseSubscription>();
foreach (UserSubscription sub in db.UserSubscriptions)
{
if (sub.ID == id)
{
user_Course_subscriptions.Add(sub.CourseSubscription);
}
}
List<CourseSubscription> not_subscribe = db.CourseSubscriptions.Except(user_Course_subscriptions);
var coursesList = from courses in not_subscribe
select new SelectListItem
{
Text = courses.Course.Name,
Value = courses.Course.ID
.ToString()
};
var CoursesTYPE = from CourseTypes in db.CourseTypes.ToList()
select new SelectListItem
{
Text = CourseTypes.Name,
Value = CourseTypes.ID
.ToString()
};
ViewBag.CourseID = coursesList;
ViewBag.type = CoursesTYPE;
return View(model);
}
I am trying to find Course Subscription that are not subscribe by the current user by using the above code but its not working?
You're missing ToList on the results from your Except function. Do a ToList like so:
List<CourseSubscription> not_subscribe = db.CourseSubscriptions.Except(user_Course_subscriptions).ToList();
Or since in your code you're not doing anything that needs a list, simply var it or assign the correct type to it such as IQueryable<CourseSubscription> to it.
var not_subscribe = db.CourseSubscriptions.Except(user_Course_subscriptions);
I have an ActionResult that returns a View with a grid that show notes from a database. On the same page there is a button to call CreateNote, which returns a PartialView where I can add new notes. This all works, but after adding the new note I want the view to go back to the TabNotes showing the grid.
I tried using
return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri);
but this goes to the wrong page. So instead I want to return the TabNotes ActionResult. Is this possible?
public ActionResult CreateNote(
[ModelBinder(typeof(Models.JsonModelBinder))]
NoteModel Model, string cmd, long? itemId, string modelEntity)
{
if (cmd == "Save")
{
Model.meta.message = "Note saved";
//standard user = 1, needs to be changed to variable
test.Database.User User = UserRepository.GetUser(1);
Entity entity = NotesRepository.GetEntity("Phrase");
NotesRepository.StoreNote(Model.subject, Model.text, User, entity, itemId);
return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri);
}
Model.meta.modelname = "CreateNote";
Model.meta.JsViewModelType = "EditNoteModel";
Model.meta.PostAction = Url.Action("CreateNote", new { cmd = "Save", itemId = itemId});
return PartialView("CreateNotePartial",Model);
}
'
public ActionResult TabNotes([ModelBinder(typeof(Models.JsonModelBinder))]
TabNotesModel Model, string cmd)
{
Entity entity = NotesRepository.GetEntity(Model.meta.entity);
if (Model.meta.id.HasValue)
{
Model.meta.modelname = "TN" + Model.meta.entity + Model.meta.id.Value.ToString();
Dictionary<string, object> defaultValues = new Dictionary<string, object>();
defaultValues.Add("Entity", entity.EntityId);
defaultValues.Add("ItemId", Model.meta.id.Value);
Entity noteEntity = NotesRepository.GetEntity("Note");
var grid = UI.GetEntityFlexiGrid(noteEntity, true, true, true, true, defaultValues);
grid.buttons.Clear();
grid.title = "";
Model.Grid = grid;
Model.Grid.url = Url.Action("TabNoteData", new { id = Model.meta.entity, itemId = Model.meta.id.Value});
}
return View("TabNotes", Model);
}
You should redirect to the action:
return RedirectToAction("TabNotes");
im trying to get the values of all the checked checkboxes and post those values(integer) to an action result, the problem is i get an empty array at the controller side ...
my jquery code is as follow:
function getIds() {
var idList = new Array();
var loopCounter = 0;
//find all the checked checkboxes
$("input:checked").each
(
function() {
//fill the array with the values
idList[loopCounter] = $(this).val();
loopCounter += 1;
}
);
//Send the list off
alert(idList);
var postData = { values: idList };
$.post("/Admin/Delete/", postData);
}
my controller side code is following
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(Int32[] values)
{
try
{
// TODO: Add delete logic here
return RedirectToAction("NewSubDashboard");
}
catch
{
return View();
}
}
there is no problem with the posting but im gettin an empty array at the controller side...
Shouldn't your $.post be:
$.post("/Admin/Delete/", postData);
Since postData:idList is probably undefined.
i extracted the values from httpcontext as
HttpContext ctx = System.Web.HttpContext.Current;
string[] ValArr = ctx.Request.Params.GetValues(0);