Generate jQuery functions dynamically mvc 4 razor - c#

Currently, I am passing a list of object from controller to a view, and generate labels by the object's name.
What I am trying to do is to generate a jQuery function that will Dynamically create functions (toggle a form with relative lable id) for each label after being clicked.
The jQuery function is not working, I could not output the corrent jQuery function in the webpage...... Could you give me soem hints?
<table>
#foreach (var item in Model)
{
<tr>
<td>
#Html.Label(item.productName, new { #id = item.productId})
</td>
</tr>
}
</table>
<script type="text/javascript">
$(document).ready(function () {
#foreach (var item in Model)
{
$(#item.productId).click)(function({
//do something
}));
}
});
</script>
Thanks very much!

your JS syntax is wrong, for starters. What you want to do is to give all those labels a class name (such as product_lbl) or a data attribute (if you don't like semantic class names) such as product-lbl. This way you don't have to do a second loop to add click event handlers. You'll only need one, like so:
$('.product_lbl').on(
'click',
function() { /* Do something for whichever label was clicked */ }
);
OR
$('[product-lbl]').on(
'click',
function() { /* Do something for whichever label was clicked */ }
);

Related

How to add an item to a list in a ViewModel using Razor and .NET Core?

So here's my situation.
Let's say I have a view called TheView.cshtml. TheView.cshtml has a ViewModel called TheViewModel.cs. In TheViewModel.cs, resides a List of an object (TheObject) called TheObjectList.
I have an editor template for TheObject called TheObject.cshtml. Using this editor template, I can simply display all of the items in the TheObjectList with #Html.EditorFor(model => model.TheObjectList).
However, now I want to add objects to this list dynamically. I have an AJAX function, which calls a simple partial view to give the user a blank row to add a new "TheObject", however, any new TheObject I add dynamically is not considered part of the original TheObjectList.
This is because each item in the original TheObjectList is created with a certain prefix based on its index in the original list, whereas each new dynamic TheObject is created without a prefix, thus Razor does not see it as part of the list.
Is there a way around this?
TheView.cshtml
#model Models.ViewModels.TheViewModel
<table id="Table">
<tbody>
#Html.EditorFor(m => m.TheObjectList);
</tbody>
</table>
<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
TheViewModel.cs
public class TheViewModel
{
public List<TheObject> TheObjectList { get; set; }
}
AddObject Controller Method
public IActionResult AddObject()
{
return PartialView("_EmptyRow", new TheObject());
}
AJAX Method to Add Object
$('#AddObject').click(function () {
$.ajax({
url: 'AddObject',
cache: false,
success: function (data) {
$('#Table > tbody').append(data);
},
error: function (a, b, c) {
alert(a + " " + b + " " + c);
}
});
});
You basically needs to generate/return markup which looks same as what the editor template generates for your form fields except for the element index . You need to pass the index from client side which will be a part of the form field name.
Let's assume your editor template looks like below and your TheObject has a GroupName property
#model TheObject
<div>
#Html.HiddenFor(x => x.GroupName)
#Html.TextBoxFor(s=>s.GroupName,new {#class="thingRow"})
</div>
Now when you render your page with your current code, Editor template will generate input fields like this
<input class="thingRow" id="TheObjectList_0__GroupName"
name="TheObjectList[0].GroupName" type="text" value="Something">
where 0 will be replaced with the index of the items in your TheObjectList collection.
Now let's say you already have 5 items in the collection, So when user clicks add button, you want to generate markup like above except 0 will be replaced with 5(for the sixth item). So let's update the ajax call to include the current number of items.
$('#AddObject').click(function () {
var i = $(".thingRow").length;
$.ajax({
url: 'AddObject?index=' + i,
success: function (data) {
$('#Table > tbody').append(data);
},
error: function (a, b, c) {
console.log(a, b, c);
}
});
});
That means, we need to accept the index value in our action method. Since we need to pass this index value from action method to our view to build the input field name value, I added a property to your class called Index
public ActionResult AddObject(int index)
{
return PartialView("_EmptyRow", new TheObject { Index = index});
}
Now in your _EmptyRow partial view,
#model TheObject
<input id="TheObjectList_#(Model.Index)__GroupName"class="thingRow"
name="TheObjectList[#(Model.Index)].GroupName" type="text" value=""/>
Now when you submit the form, model binding will work for these dynamically added items, assuming you have your Table inside a form.
#model TheViewModel
#using (Html.BeginForm())
{
<table id="Table">
<tbody>
#Html.EditorFor(m => m.TheObjectList);
</tbody>
</table>
<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
<button type="submit" class="btn btn-primary">Save</button>
}

How to filter data from dynamically generated list?

Currently I am working on one web application in asp.net.
Application received data from web-service in json format. Requirement is to develop controls dynamically, I did it using html controls. I dynamically created list of label & stored values in it. Now I want to add filter on the top of that list so that it can filter data based on vales entered in the textbox.
I want something like below textbox list of data like item1, item2 and so on, based on value entered in textbox. I need to filter data.
How I can achieve this?I tried to use list.js but it didn't work.
<% foreach (var item in (List<string>)Session["list"])
{
%>
<%--<li><label onclick="redirect('<%:item %>')"><%: item %></label><br/></li>--%>
<li><%:item %></li>
<% } %>
Add texbox with onkeyup event handler, set some id to ul e.g. id="list"
<input type="text" onkeyup="filter(this)" />
<ul id="list">
<li>a</li>
<li>abc</li>
<li>bcd</li>
<li>abc</li>
</ul>
Add the following script (source) and a reference to jquery
<script>
function filter(element) {
var value = $(element).val();
$("#list > li").each(function() {
if ($(this).text().search(value) > -1) {
$(this).show();
}
else {
$(this).hide();
}
});
}
</script>
Demo: http://jsbin.com/hahodetu/1/edit?html,output

Calling Javascript functions from href defined in Razor file

So I have this function cart.remove(itemid), that removes an item from the shopping cart using an ajax call. The cart object is defined in its own javascript file and its functions are accessible and the remove() function works properly to remove items as intended. Upon clicking the link below, an alert pops up, confirming if you really want to remove the item. If yes, it removes the item from the shopping cart.
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
<div><a title="Remove item from cart" href="javascript:cart.remove(#(item.ItemID));">Remove Item</a></div>
}
}
Now, due to complexity of the different types of items in the shopping cart, for a more user friendly UI, I need the confirm-remove-item alert text to be different, depending on the item that is clicked. I have a function defined in the model, GetRemoveItemAlertText(int itemid) that returns the appropriate text. I wrap that text in a json object so that the text isn't visible as one of the remove() function's parameters, when someone hovers over the link, in the browser statusbar.
The javascript remove() function has been redefined to remove(itemid, alerttext) to display the custom remove text, instead of the same text every time. No other changes to that function; it still displays an alert and removes the item if the user clicks yes to the confirmation. Here is my attempt at removing the item with the custom alert text:
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
var alert = Model.GetRemoveItemAlertText(item.ItemID);
<script type="text/javascript">
function removeItem_#(item.ItemID)() {
var bodytext = "#UriEscapeDataString(alertText)";
var alerttext = {
bodytext: bodytext
};
cart.remove(#(item.ItemID), alerttext);
}
</script>
<div><a title="Remove item from cart" href="javascript:cart.removeItem_#(item.ItemID)();">Remove Item</a></div>
}
}
Since the javascript function is defined inside a loop, the name needs to be different each time, hence the itemid in the function name. It should grab the custom remove-item text and then call cart.remove(), just like it was previously being done inside the href definition. The problem is that this function removeItem_#(item.ItemId)() is not being called. Even if I just put an alert() or console.log() inside the function, the code never fires. Is there anyway to accomplish this? I've also tried calling that function by using a click listener bound to a class that is on a <span>' or`. Any suggestions? I can clearly see, by viewing the page source, that each of the cart's current items have their own remove-item function defined, but for some reason, the code isn't reachable.
Try this on for size, of course all of this can be done MUCH easier with JQuery if you would like a much better solution:
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
<div><a title="Remove item from cart" id="#item.ItemID" hreaf="javascript:return RemoveItem(#item.ItemID);" data-message="#Model.GetRemoveItemAlertText(item.ItemID)">Remove Item</a></div>
}
}
<script>
function RemoveItem(itemId)
{
var element = document.getElementById(itemId.toString());
var alerttext = element.getAttribute('data-message');
return cart.remove(#(item.ItemID), alerttext);
}
</script>
Much better if we can use JQuery:
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
<div><a title="Remove item from cart" href="#" class="cart-item" data-itemid="#item.ItemID" data-message="#Model.GetRemoveItemAlertText(item.ItemID)">Remove Item</a></div>
}
}
<script>
$(document).ready(function(){
$('.cart-item').click(function(e){
e.stopProgagation();
cart.remove($(this).data('itemid'), $(this).data('message'));
});
});
</script>

How to bind jQuery event when ASP.NET MVC renders Model

I have following HTML code under Requisition.cshtml
foreach (var item in Model.RequisitionWorks)
{
<tr>
<td><div class="radio"><label name="#string.Format("Option_{0}", item.OptionNumber)">#item.OptionNumber</label></div></td>
<td>
<div class="radio">
<label>#Html.RadioButton(string.Format("Option_{0}", #item.OptionNumber),
"0", #item.IsOptionChecked("0"), new { #class = "OptionClass", id = string.Format("Option_None_{0}", #item.ToothNumber) }) #MyModelEntities.Properties.Resource.None
</label>
</div>
</td>
And I generate lots of radiobuttons...
So I would like to bind some jQuery event at the moment of rendering that code.
$("#Option_None_" + optionNumber).change(function () {
});
I need it because I generate id of html tag on fly.
Is it possible to do?
Why not apply using the class of the option instead of an id?
$(document).ready(function(){
$(".OptionClass").change(function () {
});
});
You can do this by using the .on jquery method (http://api.jquery.com/on/). To accomplish this you would select your containing div and then set the onchange for the inputs within it.
$('div.radio').on('change', 'input', function() {});
Edit: it's a lot easier to do what you want to if you give the radio buttons a common class and use the above method. Generally it's not necessary use something unique like the id to attach the same event handler to each one.

Issues with toggleclass in jquery

I have a condition , where i have to use toggle class plus delete the class of all other list in a drop down menu ,
for instance if i select any product from the list , all the other products background position should be 0,0 , also on clicking the
same selected product again the bacground position should go back to 0,0. something similar to toggle . I just cant get the both functionality work together.
any ideas on how to get it working or any other way of doing it below is the code which i have tried so far:
for toggle i used the following jquery code :
<script type="text/javascript">
$(document).ready(function() {
$('.option-list.swatch.brass label').on("click", function() {
$(this).toggleClass('not-selected selected-value');
});
});
</script>
To change the background position of all the other list labels apart from the selected ones
<script type="text/javascript">
$(document).ready(function() {
$('.option-list.swatch.brass label').on("click", function() {
$(".option-list.swatch.brass label").each(function() {
$(this).css("background-position", "0px 0px");
});
$(this).css("background-position", "0px 50px");
});
});
</script>
<ul>
#foreach (var pvaValue in attribute.Values)
{
<li>
<label for="" class="not-selected" style="background-image:url(#(pvaValue.MenuIcon));width:50px;height:49px;">#pvaValue.Name</label>
}
</li> </ul>
<style type="text/css">
label.not-selected{background-position:0px 0px;}
label.selected-value{background-position:0px 50px;}
</style>
It is occurring because of Javascript conflict. The one which is called earlier will be overridden by later click bound function..
I would say, combine the logic from both the click bounds..
$('.option-list.swatch.brass label').on("click", function() {
//FIRST LOGIC
$(this).toggleClass('not-selected selected-value');
//SECOND LOGIC
$(".option-list.swatch.brass label").each(function() {
$(this).css("background-position", "0px 0px");
});
$(this).css("background-position", "0px 50px");
});
This should solve your problem. It's okay to call both the logic in one click event function. :-)

Categories