5

I need to use jQuery to add some elements dynamically. So I looked up in the internet and I found this. It is nice and working when there is plain html elements inside single quotes. I need to use razor syntax with jQuery.

I understand that jQuery is user side and razor is server side. They cannot be combined together. I am asking here because I need to know how do i achieve this.

My not working jQuery is as follows:

<script type="text/javascript">  
    $(document).ready(function () {  
        $(document).on("click", ".btnPlus", function () { 
        var html = '<div class="form-group">'+
                '@Html.LabelFor(model => model.transaction_item, "transaction_item", htmlAttributes: new { @class = "control-label col-md-2" })'+ 

                '<div class="col-md-4">'+
                    '@Html.DropDownList("transaction_item", null, htmlAttributes: new { @class = "form-control" })'+
                    '@Html.ValidationMessageFor(model => model.transaction_item, "", new { @class = "text-danger" })'+
                '</div>'+

                '<div class="col-md-6"><input type="button" class="BtnPlus" value="+" /></div>'+

            '</div>'
        $("#trItem").append($(html))
    };
});

My aim is similar to the tutorial - to add elements dynamically. Here I am adding a label and dropdown on the click of button. How do I achieve this?

Nisarg
  • 13,121
  • 5
  • 31
  • 48
Gaurav Chauhan
  • 1,172
  • 3
  • 13
  • 33
  • Do you get any errors in your browser's developer tools? – Zaki Dec 03 '15 at 11:04
  • Refer the answers [here](http://stackoverflow.com/questions/29161481/post-a-form-array-without-successful/29161796#29161796) and [here](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) for some options for dynamically adding collection items –  Dec 03 '15 at 11:04
  • This is a really bad idea for multiple reasons. Instead use Razor to generate a templated snippet of HTML (hidden in the DOM) and use jQuery to copy that. – Gone Coding Dec 03 '15 at 11:08
  • 1
    @Zaki it was "Unidentified symbol" in chrome`s developer tool... – Gaurav Chauhan Dec 03 '15 at 11:08
  • 1
    @TrueBlueAussie that looks promising. How do i do that? Any docs/tuts/links....Thanks... – Gaurav Chauhan Dec 03 '15 at 11:10
  • @GauravChauhan the tutoiral you are following is just showing you how to do this in jquery follow this tutorial it shows you proper way - with templates : http://www.itorian.com/2013/04/nested-collection-models-in-mvc-to-add.html – Zaki Dec 03 '15 at 11:14
  • Creating a partial view and appending the above data into html using Jquery load method would suitable for this case. – Suprabhat Biswal Dec 03 '15 at 11:29
  • @Zaki exact error "Uncaught SyntaxError: Unexpected token ILLEGAL"... – Gaurav Chauhan Dec 03 '15 at 11:40
  • @SuprabhatBiswal i just tried it as shown by @firste`s answer. got the error in chrome developer tools: Uncaught SyntaxError: Unexpected token ILLEGAL – Gaurav Chauhan Dec 03 '15 at 11:41
  • @GauravChauhan: Not like that just create in normal way. It doesn't seem correct. Here's an example [Rendering Partial View](http://www.codeproject.com/Articles/821330/Work-with-Partial-view-in-MVC-framework). Another good example is shown here [Rendering Partial View Using Jquery](http://www.binaryintellect.net/articles/218ca630-ba50-48fe-af6e-6f754b5894aa.aspx) – Suprabhat Biswal Dec 03 '15 at 11:49
  • Added an example of what I meant below. – Gone Coding Dec 03 '15 at 12:26

3 Answers3

5

You cannot add Razor elements using JQuery because, as you have stated, JQuery is a client side library and ASP.NET using Razor syntax is a server side scripting language.

If you want to add elements created using Razor syntax then add a hidden element to the page and use JQuery to add a clone of it to the DOM.

Something like this should give you an idea of what I mean:

@Html.DropDownList("transaction_item", null, htmlAttributes: new { @class = "form-control", @id = 'template-ddl' })

$("#trItem").append($('#template-ddl').clone());
AGB
  • 2,200
  • 16
  • 31
5

You can create a partial page _MyPartial.cshtml in your Views Shared folder.

Then in your view reference add the reference to your scripts section

@section Scripts {
    @Html.Partial("~/Views/Shared/_MyPartial.cshtml",Model);
}

Partial page: _MyPartial.cshtml

@model MyViewModel

<script type="text/javascript">  
$(document).ready(function () {  
    $(document).on("click", ".btnPlus", function () { 
    var html = '<div class="form-group">'+
            '@(Html.LabelFor(model => model.transaction_item, "transaction_item", htmlAttributes: new { @class = "control-label col-md-2" }))'+ 

            '<div class="col-md-4">'+
                '@(Html.DropDownList("transaction_item", null, htmlAttributes: new { @class = "form-control" }))'+
                '@(Html.ValidationMessageFor(model => model.transaction_item, "", new { @class = "text-danger" }))'+
            '</div>'+

            '<div class="col-md-6"><input type="button" class="BtnPlus" value="+" /></div>'+

        '</div>'
    $("#trItem").append($(html))
};
</script>
devfric
  • 6,566
  • 6
  • 33
  • 51
3

It is best to avoid generating jQuery/Javascript code with Razor. For many reasons your Javascript/jQuery code is better off in separate files (VS debugging/script bundling etc)

Instead inject the templated HTML into a hidden part of the page. A dummy script block works great for this as the browser will just ignore an unknown script type:

<script id="template" type="text/template">  
    <div class="form-group">
        @Html.LabelFor(model => model.transaction_item, "transaction_item", htmlAttributes: new { @class = "control-label col-md-2" })    
        <div class="col-md-4">
            @Html.DropDownList("transaction_item", null, htmlAttributes: new { @class = "form-control" })
            @Html.ValidationMessageFor(model => model.transaction_item, "", new { @class = "text-danger" })
        </div>
        <div class="col-md-6"><input type="button" class="BtnPlus" value="+" /></div>
    </div>
</script>

You can see what is generated with your DOM inspector to ensure the correct attributes are present.

Then simply use that HTML from the template to add new buttons:

$("#trItem").append($('#template').html());

The only issue you need to resolve is any duplicate IDs and indexing for multiple items. I usually use raw HTML in the template (not Razor) and use placeholders for the various attributes that need renaming.

e.g.

<script id="template" type="text/template">  
    <div class="form-group">
        <label for="{id}"/>
Gone Coding
  • 88,305
  • 23
  • 172
  • 188
  • so, how one should approach this problem these days, I was wondering what client side code to use with my razor website, vanilla js, jquery angular, react, knockout I kinda like the simplicity of the first two – Vitaliy Terziev Mar 17 '17 at 21:00
  • @ВиталийТерзиев: It depend of which stack you wish to use. If you use Angular, you won't be inject much of anything into the hosting page as it is all client-script driven with data via service calls. Can you provide an example of what you want to inject? – Gone Coding Mar 22 '17 at 13:14
  • Actually I was wondering if i can skip angular, use Razor with just enough JS, for example knockout or jquery, it is a simple company site and I just want to look good and was wondering if this is a bad practice – Vitaliy Terziev Mar 23 '17 at 07:08
  • @ВиталийТерзиев: There is a push towards client-side frameworks, like Angular, in a lot of companies, but the invisible overheads (proper testing) are large. Myself, I added plugin layers of JS on top of MVC so that it operates like Angular (but with half the calories) :) – Gone Coding Mar 23 '17 at 08:54
  • Yes, thank you for your answers, I guess I will give it a try and see how it goes :) hopefully I will get by with several js functions (the site will be really simple and my goal is smooth, fast experience, after all the site is going to sell web apps, sites and e-commerce (this will be little bit harder but nppcommerce seems very good :) ) – Vitaliy Terziev Mar 23 '17 at 13:49