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.
Related
I need some help. How can I add new values in code to the list if I use a plugin from jquery. I wrote this code, but the list is empty, although the values are passed to the view. This is probably due to the fact that I am referring to the id of the div tag, but the plugin did not work differently. Help please
<html>
<main>
<form action="#">
<div class="form-group col-xs-12 col-sm-4" id="example-2"> </div>
</form>
</main>
<script>
$('#example-2').selectivity({
items: ['Amsterdam', 'Antwerp'],
multiple: true,
placeholder: 'Type to search a city'
});
function addOption() {
var ul = document.getElementById("#example-2");
for (var item in #ViewBag.List)
{
var value = item;
}
var newOption = new Option(value, value);
ul.options[ul.options.length] = newOption;
}
</script>
</html>
result of code from answer 1
The documentation of the selectivity library covers how to add new options to the dropdown.
The main issue you have is that the output from #ViewBag.List won't be in a format that JS can understand. I would suggest formatting it as JSON before outputting it to the page, then the JS can access this as a standard object, though which you can loop.
// initialisation
$('#example-2').selectivity({
items: ['Amsterdam', 'Antwerp'],
multiple: true,
placeholder: 'Type to search a city'
});
// add options, somewhere else in your codebase...
const $list = $('#example-2')
const options = #Html.Raw(Json.Encode(ViewBag.List));
options.forEach((option, i) => {
$list.selectivity('add', { id: i, text: option })
});
Note that for this to work the JS code which reads from the ViewBag needs to be placed somewhere the C# code will be executed, ie. in a .cshtml file, not in a .js file.
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)
I'm strugling with a jquery script inside a cshtml page. For short my question is how to use a var inside a # statement in a cshtml page?
below an example of what I'm trying:
<select id="DefaultText">
<option value="-1">-- select --</option>
#foreach( var d in Model.DefaultTexts )
{
<option value="#d.Id" >#d.Name</option>
}
</select>
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
var text = #Model.DefaultTexts.First( t => t.Id == id );
$('#CustomProductText').val(text);
});
</script>
I can't reach the var id. It's out of scope. I've also tryed it with a for loop and a if statement. But in the if statement I get the same error: out of scope.
The full story is this:
On my page I've a dropdown list. The items to select are short names for default text parts. Based on the id or name, I want to show the default text part in a textbox.
#CustomProductText is my textbox where the content should be placed (code not posted).
I've also tryed it with #: and statement but that did not work.
What am I doing wrong or maybe its not even possible what I'm trying to do.
As an alternative I've added a action to my controller to get the text form there. Below the code:
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
$.post("Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
//$('#CustomProductText').val(text);
});
</script>
controller code:
[HttpPost]
public ActionResult GetDefaultText(int id)
{
using( var context = new MyContext() )
{
var text = context.DefaultText.First( d => d.Id == id ).Text;
return this.Content( text );
}
}
This doesn't work. The action doesn't get hit in debug mode.
regards,
Daniel
The $.post that is not working for you, you should prefix the url with / sign and it will be hit as expected:
$.post("/Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
As for the razor solution, you can't use javascript variables in the razor code as it's not a scripting language. What razor does is simply rendering the strings (be it html or javascript or anything) into the page.
To do what you want you either need to request the server to pass the text to your page or render all the texts you have in the page and then access this rendered content in your javascript.
I'm experiencing some issues with a cascade dropdownlist (ASP.Net MVC Razor), i know there are many questions answered on this topic but mine is quite different and i couldn't find an answer after hours of search.
I have my PessoaController (PersonController) which is inside an area named requerente.
I have two dropdownlists one for the provinces (Província) and other for the suburbs (Município).
Belown is the code i have on my view:
<div class="editor-label">
#Html.LabelFor(model => model.ProvinciaId, "Província")
</div>
<div class="editor-field">
#Html.DropDownListFor(Model => Model.ProvinciaId, new SelectList(ViewBag.ProvinciaId as System.Collections.IEnumerable, "id", "Valor"),
"Seleccione", new { id = "ddlProvincia" })
#Html.ValidationMessageFor(model => model.ProvinciaId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.MunicipioId, "Município")
</div>
<div class="editor-field">
#Html.DropDownListFor(Model => Model.MunicipioId, new SelectList(ViewBag.MunicipioId as System.Collections.IEnumerable, "Id", "Valor"),
"Seleccione", new { id = "ddlMunicipio" })
#Html.ValidationMessageFor(model => model.MunicipioId)
</div>
and this is the javascript code that calls the function on my controller
<script type="text/javascript">
$(document).ready(function () {
$("#ddlProvincia").change(function () {
var selectedProvinceId = $(this).val();
$.getJSON("../pessoa/LoadMunicipiosByProvinceId", { provinciaId: selectedProvinceId },
function (municipioData) {
var select = $("#ddlMunicipio");
select.empty();
select.append($('<option/>', {
value: 0,
text: "Escolha o Municipio"
}));
$.each(municipioData, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
});
});
});
});
</script>.
This code works perfectly (on the create view), when i want to add a new person i select the province and it loads the suburbs according to the selected province, so far so good.
To avoid having to duplicate the javascript function by copying the code to the edit view, i decided to move my javascript function to a partial view and include it in both the create and edit view.
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Html.Partial("LoadMunicipiosScript");
}
The code still runs perfectly on the create view, but on the edit view, whenever i select a different province i get a 404 error because the function cannot be found.
From firebug i can see what the problem is, my create view uses the right path to invoke the function in the controller.
localhost:57934/requerente/pessoa/LoadMunicipiosByProvinceId?provinciaId=200003
How ever on my edit view somehow the name of my controller is added twice to the path, and thus results in a 404.
localhost:57934/requerente/pessoa/pessoa/LoadMunicipiosByProvinceId?provinciaId=200003
I know that duplicating the code and tweaking the url would get me up and running but does anyone has any idea why the inconsistent behavior, having into count that both views (create and edit) are on the same folder and are executing the same shared function.
The problem looks like you have the same relative URL ../pessoa/LoadMunicipiosByProvinceId loading from two different pages which ends up referring to a different place in each. This would happen if, for example, your two URLs are (note the different base folder):
localhost:57394/requerente/foo
localhost:57394/requerente/pessao/bar
Instead, you can use Url.Action to dynamically generate the target URL. I do not know your routing scheme, but for example:
$.getJSON("#Url.Action("LoadMunicipiosByProvinceId", "pessoa")",
{ provinciaId: selectedProvinceId },
function(data) {/*...*/});
I have a ASP.NET MVC 4 app with model, that contains and colection (IEnumerable<T> or IList<T>), i.e.:
class MyModel
{
public int Foo { get; set; }
public IList<Item> Bar { get; set; }
}
class Item
{
public string Baz { get; set; }
}
And I render the data in view with classic #for..., #Html.EditorFor... ad so on. Now there's a need to add on client side to add dynamically new items and then post it back to server.
I'm looking for an easy solution to handle the adding (in JavaScript), aka not manually creating all the inputs etc. Probably to get it somehow from editor template view. And to add it the way that when the form is submitted back to server the model binder will be able to properly create the IList<T> collection, aka some smart handling of inputs' names. I read a bunch of articles, but nothing that was easy and worked reliably (without magic strings like collection variable names, AJAX callbacks to server, ...).
So far this looks promising, but I'd like to rather rely on rendering (items known in advance) on server.
I'm not sure what do you mean 'collection variable names' and probably my solution is kind of magic you noticed.
My solution is based on copying existing editor for element and altering input names via Javascript.
First of all, we need to mark up our editor. This is a code of form outputs editor for collection
#for (var i = 0; i < Model.Count; i++)
{
<div class="contact-card">
#Html.LabelFor(c => Model[i].FirstName, "First Name")
#Html.TextBoxFor(c => Model[i].FirstName)
<br />
#Html.LabelFor(c => Model[i].LastName, "Last Name")
#Html.TextBoxFor(c => Model[i].LastName)
<br />
#Html.LabelFor(c => Model[i].Email, "Email")
#Html.TextBoxFor(c => Model[i].Email)
<br />
#Html.LabelFor(c => Model[i].Phone, "Phone")
#Html.TextBoxFor(c => Model[i].Phone)
<hr />
</div>
}
Our editor is placed into div with class contact-card. On rendering, ASP.NET MVC gives names like [0].FirstName, [0].LastName ... [22].FirstName, [22].LastName to inputs used as property editors. On submitting Model Binder converts this to collection of entities based both on indexes and property names.
Next we create javascript function that copies last editor and increases index in brackets by 1. On submitting it adds additional element to collection:
var lastContent = $("#contact-form .contact-card").last().clone();
$("#contact-form .contact-card").last().after(lastContent);
$("#contact-form .contact-card")
.last()
.find("input")
.each(function () {
var currentName = $(this).attr("name");
var regex = /\[([0-9])\]/;
var newName = currentName.replace(regex, '[' + (parseInt(currentName.match(regex)[1]) + 1) + ']');
$(this).val('');
$(this).attr('name', newName);
});
VOILA!! On submitting we will get one more element!
At the end I did similar stuff what STO was suggesting, but with the custom (non-linear) indices for collections suggested by Phil Haack.
This uses manual naming of elements (so I'm not binding directly to the model) and I can use custom instances (for empty element templates). I've also created some helper methods to generate me the code for the instance, so it's easier to generate code for actual instances from the model or empty ones.
I did this with help of Backbone (for file uploader) where i insert template whenever user click #addButton
View:
#using Telerik.Web.Mvc.UI
#{
ViewBag.Title = "FileUpload";
Layout = "~/Areas/Administration/Views/Shared/_AdminLayout.cshtml";
}
<div id="fileViewContainer" class="span12">
<h2>File upload</h2>
#foreach(var fol in (List<string>)ViewBag.Folders){
<span style="cursor: pointer;" class="uploadPath">#fol</span><br/>
}
#using (Html.BeginForm("FileUpload", "CentralAdmin", new { id = "FileUpload" }, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<label for="file1">Path:</label>
<input type="text" style="width:400px;" name="destinacionPath" id="destinacionPath"/><br />
<div id="fileUploadContainer">
<input type="button" class="addButton" id="addUpload" value="Add file"/>
<input type="button" class="removeButton" id="removeUpload" value="Remove file"/>
</div>
<input type="submit" value="Upload" />
}
</div>
<script type="text/template" id="uploadTMP">
<p class="uploadp"><label for="file1">Filename:</label>
<input type="file" name="files" id="files"/></p>
</script>
#{
Html.Telerik().ScriptRegistrar().Scripts(c => c.Add("FileUploadInit.js"));
}
FileUploadInit.js
$(document).ready(function () {
var appInit = new AppInit;
Backbone.history.start();
});
window.FileUploadView = Backbone.View.extend({
initialize: function () {
_.bindAll(this, 'render', 'addUpload', 'removeUpload', 'selectPath');
this.render();
},
render: function () {
var tmp = _.template($("#uploadTMP").html(), {});
$('#fileUploadContainer').prepend(tmp);
return this;
},
events: {
'click .addButton': 'addUpload',
'click .removeButton': 'removeUpload',
'click .uploadPath': 'selectPath'
},
addUpload: function (event) {
this.render();
},
removeUpload: function (event) {
$($('.uploadp')[0]).remove();
},
selectPath: function (event) {
$('#destinacionPath').val($(event.target).html());
}
});
var AppInit = Backbone.Router.extend({
routes: {
"": "defaultRoute"
},
defaultRoute: function (actions) {
var fileView = new FileUploadView({ el: $("#fileViewContainer") });
}
});
In Controller you keep your code
I Hope this will help.