DropDownList multiple data - javascript

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() );
})
})

Related

pass ViewBag to js function

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)

For Loop in MVC 4 From JavaScript value

How can I make a repeater type in the page. In the page I have a quantity field:
<td>
#Html.DisplayNameFor(x => x.Quantity)
#Html.ValidationMessageFor(x => x.Quantity)
</td>
<td>
#Html.TextBoxFor(x => x.Quantity, new { #id = "txtQty" })
</td>
When I want to add the item, which there could be several of the same item, just different serial numbers, I need to pop open a div with repeated fields for entering serial numbers:
for (int I = 0; I < *****; I++)
{
<td>Serial Number:</td>
<td>#Html.TextboxFor(x=>x.Quantity, new { #id = "txtQty" + 1})
}
In the JS:
function AddItem() {
Qtys = parseINT($("#txtQty").val());
$("#divSerials").show();
}
How can I do this? Is there a better way?
Is this the way to do it? I try this but 'i' in the HTML model statement is not recognized.
if (parseInt($("#txtQuantity").val()) > 0) {
$("#divSerialNumbers").show();
var html = "<table>";
for (i = 1; i <= serialquantity; i++) {
html += "<tr><td>Serial Number:" + #Html.TextAreaFor(x => x.SerialNumber, new { id = "sns" + i }) + "</td></tr>";
}
html += "</table>";
$("#divSerialNumbers").html(html);
}
Razor code is parsed on the server before it is sent to the view. Javascript is client side code and is not executed until the browser receives the view. This line of code
#Html.TextAreaFor(x => x.SerialNumber, new { id = "sns" + i })
means that on the server you are trying to generate a textarea and set the id attribute to a value that includes a javascript variable which does not yet exist.
Its unclear even what the point of this would be. id attributes serve as selectors in javascript. Whats important is the name and value attributes when it comes to posting your data, and even if it could work, your generating duplicate name attributes which could not bind to you models collection property on post back.
For dynamically generating the html for collections, your name attributes need an indexer, for example <input type="text" name="[0].SerialNumber" />. Options for dynamically creating the html include using the BeginCollectionitem() helper, or a pure client side approach is shown in this answer
If all you are doing is post back an array of strings (the serial numbers) then you could use
var div = $("#divSerialNumbers"); // cache it
$('#Quantity').change(function() { // assumes you remove the pointless 'new { #id = "txtQty" }'
var quantity = parseInt($(this).val()); // use $(this) - don't traverse the DOM all over again
if (!isNan(quantity) && quantity > 0) { // must check for NAN
// note it does not seem necessary to use a table, as opposed to simply adding 4 inputs to the div, but
div.empty(); // clear existing contents
var table = $('</table>');
for (i = 1; i <= quantity; i++) {
var input = $('<input>').attr('name', 'SerialNumber');
var cell = $('</td>').append(input);
var row = $('</tr>').append(cell);
table.append(row);
}
div.append(table).show(); // add the table and display it
}
})
and your controller would need a parameter string[] SerialNumber, for example
public ActionResult Edit(string[] SerialNumber)

chap links library - network- how to get table row id

I'm using chap links library https://github.com/almende/chap-links-library/tree/master/js/src/network for drawing an area of objects.
I want to be able to use the id that I have set to an object upon click, I have this code
function onselect() {
var sel = network.getSelection();
console.log("selected "+sel[0].row);
}
It works fine, only it retrieves the row number from the dynamically created table. I want to retrieve a value from that row (an object id that I set) but I don't know how to access it.
I have tired things like
sel[0].row.id
sel[0].row.getId()
sel[0].row[0]
But I don't know how they structure the data in their thing...
Anyonw run into this before and solved it?
This is the way I set the data
nodesTable.addRow([45, "myObjectName", "image", "images/container_icons/icon.png"]);
For my app I solved it by creating a parallel array...
//rendera objekt
window.clickHelper = []; //keep track of container id in conjunction with hierarchy-canvas-object's id
var i = 0; //counter for above
Populating it upon every node creation...
nodesTable.addRow([{{ c.id }}, "{{ c.name }}", "image", "{{ asset('images/container_icons/'~c.icon~'.png') }}"]);
clickHelper[i]={{c.id}};
i++;
Then calling in data from that array on my onSelect event...
function onselect() {
//get selected node from network
var sel = network.getSelection();
sel = sel[0].row;
//get path base structure
var path = '{{ path('editGroup') }}';
//fix path with the DB id of the clicked object
path = path+clickHelper[sel];
window.location.href = path;
}
The double {{ }} are TWIG templating for those unfamiliar with that. Mixed javascript and TWIG ServerSide code here, sorry.

Modifying Replicated EditorTemplates with Javascript

I have an Editor Template which contains a table row with (among other stuff) a dropdown/combobox to select a currency. This edit template is shown many times on the same View and it's possible for a user to add these rows as many times as he wants.
I want changes on a row's dropdown to reflect in an EditorFor (the currency's rate) on the same row, so I've added a onchange html parameter:
<td>
#*#Html.LabelFor(model => model.Currency)*#
#Html.DropDownListFor(model => model.Currency, new SelectList(Model.CurrencyList, "Code", "Code"), new { onchange = "updateCurrency(this)" })
#Html.ValidationMessageFor(model => model.Currency)
</td>
My javascript function makes an ajax call to retrieve the rate for the selected currency:
function updateCurrency(elem) {
alert("Currency changed!")
$.ajax({
type: "GET",
url: "Currency?code=" + elem.value,
success: function (msg) {
// The Rate field's Id:
var RateId = "#Html.ClientIdFor(model=>model.Rate)" // // Halp, problem is here!
document.getElementById(RateId).value = msg;
}
});
}
My problem is that
var RateId = "#Html.ClientIdFor(model=>model.Rate)"
has that Html helper which is server-side code. So when i view the page's source code, the javascript code is replicated (once for each row) and all the var RateId = "#Html.ClientIdFor(model=>model.Rate)" are pointing to the most recently added column's EditorFor.
Probably my way of attempting to solve the problem is wrong, but how can I get my javascript code to update the desired field (i.e. the field in the same row as the changed dropdown list).
I believe that one of the problems is that I have the javasript on the Editor Template, but how could I access stuff like document.getElementById(RateId).value = msg; if I did it like that?
Thanks in advance :)
Figured it out. Hoping it helps somebody:
In my view:
#Html.DropDownListFor(model => model.Currency, new SelectList(Model.CurrencyList, "Code", "Code"), new { #onchange = "updateCurrency(this, " + #Html.IdFor(m => m.Rate) + ", " + #Html.IdFor(m => m.Amount) + ", " + #Html.IdFor(m => m.Total) + ")" })
In a separate JavaScript file:
function updateCurrency(elem, RateId, AmountId, TotalId) {
var cell = elem.parentNode // to get the <td> where the dropdown was
var index = rowindex(cell) // get the row number
// Request the currency's rate:
$.ajax({
blah blah blah .........
(RateId[index - 1]).value = 'retreived value'; // Set the rate field value.
});
}
Seems to be working so far.

How to limit choice field options based on another choice field in django admin

I have the following models:
class Category(models.Model):
name = models.CharField(max_length=40)
class Item(models.Model):
name = models.CharField(max_length=40)
category = models.ForeignKey(Category)
class Demo(models.Model):
name = models.CharField(max_length=40)
category = models.ForeignKey(Category)
item = models.ForeignKey(Item)
In the admin interface when creating a new Demo, after user picks category from the dropdown, I would like to limit the number of choices in the "items" drop-down. If user selects another category then the item choices should update accordingly. I would like to limit item choices right on the client, before it even hits the form validation on the server. This is for usability, because the list of items could be 1000+ being able to narrow it down by category would help to make it more manageable.
Is there a "django-way" of doing it or is custom JavaScript the only option here?
Here is some javascript (JQuery based) to change the item option values when category changes:
<script charset="utf-8" type="text/javascript">
$(function(){
$("select#id_category").change(function(){
$.getJSON("/items/",{id: $(this).val(), view: 'json'}, function(j) {
var options = '<option value="">-------- </option>';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].optionValue + '">' + j[i].optionDisplay + '</option>';
}
$("#id_item").html(options);
$("#id_item option:first").attr('selected', 'selected');
})
$("#id_category").attr('selected', 'selected');
})
})
</script>
You need a view to be called on the /items/ URL that supplies a JSON list of the valid items.
You can hook this into your admin by using model admin media definitions.
There is django-smart-selects:
If you have the following model:
class Location(models.Model)
continent = models.ForeignKey(Continent)
country = models.ForeignKey(Country)
area = models.ForeignKey(Area)
city = models.CharField(max_length=50)
street = models.CharField(max_length=100)
And you want that if you select a continent only the countries are available that are located on this continent and the same for areas you can do the following:
from smart_selects.db_fields import ChainedForeignKey
class Location(models.Model)
continent = models.ForeignKey(Continent)
country = ChainedForeignKey(
Country,
chained_field="continent",
chained_model_field="continent",
show_all=False,
auto_choose=True
)
area = ChainedForeignKey(Area, chained_field="country", chained_model_field="country")
city = models.CharField(max_length=50)
street = models.CharField(max_length=100)
You will need to have some kind of non-server based mechanism of filtering the objects. Either that, or you can reload the page when the selection is made (which is likely to be done in JavaScript anyway).
Otherwise, there is no way to get the subset of data from the server to the client.

Categories