pass ViewBag to js function - javascript

I am having a dropdown list in which I call a js function, on change event.
In View:
#Html.DropDownList("RaceId", ViewData["Races"] as List<SelectListItem>, new { #onchange = "CallChangefunc(this.value)", #class="form-control" })
and my js:
<script>
function CallChangefunc(val)
{
//called in Index page when dropdown list changes
window.location.href = "/Index/" + val;
}
</script>
What I want is to add a new argument to my js function where I pass a ViewBag value, sth like:
#Html.DropDownList("RaceId", ViewData["Races"] as List<SelectListItem>, new { #onchange = "CallChangefunc(this.value,ViewBag.id)", #class="form-control" })
The above does not work and I am not sure which is the correct syntax, if any.

First, use unobtrusive javascript instead of onchange attribute. If you have your javascript inside your view, you can access ViewBag too, using '#ViewBag':
$('#RaceId').on('change', function()
{
var value = $(this).val();
var id = '#ViewBag.id'
}
);
Or if you're running your javascript on a different file, you can use a Hidden input and get this value in your script:
#Html.Hidden("Id", ViewBag.id)
and in you script:
$('#RaceId').on('change', function()
{
var value = $(this).val();
var id = $("Id").val();
}
);

Although Stephen's comment is 100% correct, i would just like to know if this solves your problem:
#{
var htmlAttr = new Dictionary<string, object>();
htmlAttr.Add("onchange", string.Format("{0}{1})", "CallChangefunc(this.value", #ViewBag.id));
htmlAttr.Add("class", "form-control");
}
#Html.DropDownList("RaceId", ViewData["Races"] as List<SelectListItem>, #htmlAttr)

Related

Checkbox to enable or disable a list box

I have a checkbox on my ASP.NET MVC page that I create like:
<div>
#Html.CheckBoxFor(m => m.allUsers, new { Name = "allUsersCheck" })
#Html.LabelFor(m => m.allUsers)
</div>
I also have a listbox that I create with:
#Html.ListBoxFor(x => x.selectedUsers, Model.ListofUsers, new { style = "width:200px", size = 10, Id = "lbUsers" })
I have this following script (which I wrote to disable the listbox when my checkbox is checked. I can't understand why it doesn’t work. Can someone point out what's wrong in my code please?
This script is in the same .cshtml page and not in the .js file:
<script >
$(function () {
$('#allUsersCheck').click(function () {
$('#lbUsers').prop("disabled", $(this).prop('checked'));
});
});
</script>
Because you are using the Id selector of '#allUsersCheck'. The checkbox does not have an Id attribute unlike your list box(?).
#Html.CheckBoxFor(m => m.allUsers, new { Name = "allUsersCheck" })
Try the following with an Id attribute:
#Html.CheckBoxFor(m => m.allUsers, new { Name = "allUsersCheck", Id = "allUsersCheck" })
Ok. Took me a while to figure out the entire list of things I need to do.
Here's all I did to finally get it working.
Firstly, I needed this jquery library being used.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.js"></script>
Then I had to create a function under the above jquery inclusion
<script type="text/javascript">
$(function () {
$("#allUsersCheck").change(function () {
$("#lbUsers").find("option").prop("selected", this.checked)
});
});
</script>
In the above you'll see allUsersCheck is the checkbox element's id and lbUsers is the id for the ListBoxFor element.
The next thing is, in my .cshtml I needed to use/create the listboxfor / checkbox elements. This is how I did it
<b>Users </b><br />
#Html.ListBoxFor(x => x.selectedUsers, Model.ListofUsers, new { style = "width:200px", size = 10, id = "lbUsers" })
<br />
<div>
#Html.CheckBoxFor(m => m.allUsers, new { id = "allUsersCheck" })
#Html.LabelFor(m => m.allUsers)
</div>
I also used a bool flag as part of my model. allUsers is the flag. The bool flag was needed for something else in the controller code and not for UI reasons.
I am not sure if this is the best method. But this is the method I could get it working.
Thanks to the guys who helped me in this process get this working. Obviously not without them.

DropDownList multiple data

I'm working in asp mvc c#
Now in my acp panel I have a dropdownlist:
#Html.DropDownList("id", new SelectList(ViewBag.DruhyOdznaku, "Id", "Name"), new {#onchange = "functionChange()", #class = "form-control", id = "ddlViewBy"})
I can access the name value of selected item from JS like:
function functionChange() {
var e = document.getElementById("ddlViewBy");
var finalData = e.options[e.selectedIndex];
}
Now the problem is I want to keep displaying name in the dropdown but obtain another value - in this case "Text" (from db).
How can I attach this data to the dropdown (ideally keep the way it's created) and then get them from js? Spent a day on this, my sanity going low.
Thanks a milion for help.
You can add a "data-" attribute on options. Have a look at this to see how to SelectListItem with data-attributes
But that "ideally keep the way it's created" is not going to hold.
Then you can have something like this:
$(document).ready(function(){
$("#sel").change(function(){
var selectedOption = $(this).find("option:selected");
alert(selectedOption.attr("value") + "/" +
selectedOption.data("text") + "/" +
selectedOption.html() );
})
})

How do I populate a list field in a model from javascript?

I have a Kendo.MVC project. The view has a model with a field of type List<>. I want to populate the List from a Javascript function. I've tried several ways, but can't get it working. Can someone explain what I'm doing wrong?
So here is my model:
public class Dashboard
{
public List<Note> ListNotes { get; set; }
}
I use the ListNotes on the view like this:
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
}
This works if I populate Model.ListNotes in the controller when the view starts...
public ActionResult DashBoard(string xsr, string vst)
{
var notes = rep.GetNotesByCompanyID(user.ResID, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
Dashboard employee = new Dashboard
{
ResID = intUser,
Type = intType,
FirstName = user.FirstName,
LastName = user.LastName,
ListNotes = listNotes
};
return View(employee);
}
... but I need to populate ListNotes in a Javascript after a user action.
Here is my javascript to make an ajax call to populate ListNotes:
function getReminders(e)
{
var userID = '#ViewBag.CurrUser';
$.ajax({
url: "/api/WoApi/GetReminders/" + userID,
dataType: "json",
type: "GET",
success: function (notes)
{
// Need to assign notes to Model.ListNotes here
}
});
}
Here's the method it calls with the ajax call. I've confirmed ListNotes does have the values I want; it is not empty.
public List<Koorsen.Models.Note> GetReminders(int id)
{
var notes = rep.GetNotesByCompanyID(id, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
foreach (Koorsen.OpenAccess.Note note in notes)
{
Koorsen.Models.Note newNote = new Koorsen.Models.Note()
{
NoteID = note.NoteID,
CompanyID = note.CompanyID,
LocationID = note.LocationID,
NoteText = note.NoteText,
NoteType = note.NoteType,
InternalNote = note.InternalNote,
NoteDate = note.NoteDate,
Active = note.Active,
AddBy = note.AddBy,
AddDate = note.AddDate,
ModBy = note.ModBy,
ModDate = note.ModDate
};
listNotes.Add(newNote);
}
return listNotes;
}
If ListNotes was a string, I would have added a hidden field and populated it in Javascript. But that didn't work for ListNotes. I didn't get an error, but the text on the screen didn't change.
#Html.HiddenFor(x => x.ListNotes)
...
...
$("#ListNotes").val(notes);
I also tried
#Model.ListNotes = notes; // This threw an unterminated template literal error
document.getElementById('ListNotes').value = notes;
I've even tried refreshing the page after assigning the value:
window.location.reload();
and refreshing the panel bar the code is in
var panelBar = $("#IntroPanelBar").data("kendoPanelBar");
panelBar.reload();
Can someone explain how to get this to work?
I don't know if this will cloud the issue, but the reason I need to populate the model in javascript with an ajax call is because Model.ListNotes is being used in a Kendo Panel Bar control and I don't want Model.ListNotes to have a value until the user expands the panel bar.
Here's the code for the panel bar:
#{
#(Html.Kendo().PanelBar().Name("IntroPanelBar")
.Items(items =>
{
items
.Add()
.Text("View Important Notes and Messages")
.Expanded(false)
.Content(
#<text>
#RenderReminders()
</text>
);
}
)
.Events(e => e
.Expand("getReminders")
)
)
}
Here's the helper than renders the contents:
#helper RenderReminders()
{
if (Model.ListNotes.Count <= 0)
{
#Html.Raw("No Current Messages");
}
else
{
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
<br />
}
}
}
The panel bar and the helpers work fine if I populate Model.ListNotes in the controller and pass Model to the view. I just can't get it to populate in the javascript after the user expands the panel bar.
Perhaps this will do it for you. I will provide a small working example I believe you can easily extend to meet your needs. I would recommend writing the html by hand instead of using the helper methods such as #html.raw since #html.raw is just a tool to generate html in the end anyways. You can write html manually accomplish what the helper methods do anyway and I think it will be easier for you in this situation. If you write the html correctly it should bind to the model correctly (which means it won't be empty on your post request model) So if you modify that html using javascript correctly, it will bind to your model correctly as well.
Take a look at some of these examples to get a better idea of what I am talking about:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
So to answer your question...
You could build a hidden container to hold your list values like this (make sure this container is inside the form):
<div id="ListValues" style="display:none">
</div>
Then put the results your ajax post into a javascript variable (not shown).
Then in javascript do something like this:
$('form').off('submit'); //i do this to prevent duplicate bindings depending on how this page may be rendered futuristically as a safety precaution.
$('form').on('submit', function (e) { //on submit, modify the form data to include the information you want inside of your ListNotes
var data = getAjaxResults(); //data represents your ajax results. You can acquire and format that how you'd like I will use the following as an example format for how you could save the results as JSON data: [{NoteID ="1",CompanyID ="2"}]
let listLength = data.length;
for (let i = 0; i < listLength; i++) {
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].NoteID " value="' + data.NoteID +'" />')
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].CompanyID " value="' + data.CompanyID +'" />')
//for your ajax results, do this for each field on the note object
}
})
That should do it! After you submit your form, it should automatically model bind to you ListNotes! You will be able to inpsect this in your debugger on your post controller action.

How do I access my viewmodel variables in my knockout component template?

I am trying to create a list of instruction steps using Knockout components/templates.
The UL is the going to contain a list of steps (using a knockout-registered custom element sidebar-step) which is just a template of <li></li>. I have another value this.testVar part of my model that could contain an attribute of <li> such as the class, or maybe a "data-customAttribute".
My question is, how do I include my testVar value into the template? I want it so that it might output a line like:
<sidebar-step class=*testVar* params="vm: sidebarStepModel">Message 1</sidebar-step>
Fiddle: https://jsfiddle.net/uu4hzc41/1/
HTML:
<ul>
<sidebar-step params="vm: sidebarStepModel"></sidebar-step>
</ul>
JavaScript:
ko.components.register("sidebar-step", {
viewModel: function (params) {
this.vm = params.vm;
},
template: "<li data-bind=\'text: vm.message\'></li>"
});
var SidebarStepModel = function () {
this.message = ko.observable("step description");
this.testVar = ko.observable("some value");
};
var ViewModel = function () {
this.sidebarStepModel = new SidebarStepModel();
this.sidebarStepModel.message("Message 1");
this.sidebarStepModel.testVar("69");
};
ko.applyBindings(new ViewModel());
You can use data-bind on the custom tag. To set class,
<sidebar-step data-bind="css:sidebarStepModel.testVar" params="vm: sidebarStepModel"></sidebar-step>
https://jsfiddle.net/uu4hzc41/3/

Knockout foreach binding, update value

I got ko model:
var Model = function(notes) {
this.note = ko.observableArray(notes);
};
var model = new Model([{"post":"a"},{"post":"b"}]);
ko.applyBindings(model);
And html div:
<div data-bind='foreach: note'>
<p><span data-bind='text: post'>
<p><input data-bind='value: post'>
</div>
Here's fiddle: http://jsfiddle.net/DE9bE/
I want to change my span value when new text is typed in input, like in that fiddle: http://jsfiddle.net/paulprogrammer/vwhqU/2/
But it didnt updates. How can i do that in foreach bindings?
The properties of the objects need to be made into observables.
You could do this yourself manually (i've used the plain js array map method here, if you need IE8 support you can use ko.utils.arrayMap for the same purpose):
var Model = function(notes) {
this.note = ko.observableArray(notes.map(function(note){
note.post = ko.observable(note.post);
return note;
}));
};
var model = new Model([{"post":"a"},{"post":"b"}]);
ko.applyBindings(model);
Demo
Or you can use the mapping plugin (seperate js file that you need to include) which does this (recursively) for you.
var Model = function(notes) {
this.note = ko.mapping.fromJS(notes);
};
var model = new Model([{"post":"a"},{"post":"b"}]);
ko.applyBindings(model);
Demo
If you get the whole data object from the server you could also feed it directly:
var model = ko.mapping.fromJS({
note: [{"post":"a"},{"post":"b"}]
});
ko.applyBindings(model);
Demo
What you want is an observable array with observables, or else your span will not be updated since you are changing a non-observable variable, see this post.
KnockoutJS - Observable Array of Observable objects
Try this:
HTML
<div data-bind='foreach: note'>
<p><span data-bind='text: post'></span></p>
<p><input data-bind='value: post'/></p>
</div>
JavaScript
var Model = function (notes) {
this.note = ko.observableArray(notes);
};
var Post = function (data) {
this.post = ko.observable(data);
};
var model = new Model([new Post("a"), new Post("a")]);
ko.applyBindings(model);
Demo

Categories