How to handle jquery repeater html in mvc - c#

this is my .cshtml page code,i use jquery repeater is in this code repeater is working fine but i want to add some modification in this repeater but i am stuck here. you can see my code.
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data", #class = "repeater" }))
{
<div data-repeater-list="">
<div data-repeater-item="">
<div class="col-lg-12 col-md-12 col-sm-12">
<input type="file" name="Docfiles" />
</div>
</div>
</div>
<input data-repeater-create type="button" value="Add" />
<button>Save</button>
}
#section Scripts{
<!-- Import repeater js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.repeater/1.2.1/jquery.repeater.js"></script>
<script>
$(document).ready(function () {
$('.repeater').repeater({
// (Optional)
// start with an empty list of repeaters. Set your first (and only)
// "data-repeater-item" with style="display:none;" and pass the
// following configuration flag
initEmpty: true,
// (Optional)
// "show" is called just after an item is added. The item is hidden
// at this point. If a show callback is not given the item will
// have $(this).show() called on it.
show: function () {
$(this).slideDown();
},
// (Optional)
// "hide" is called when a user clicks on a data-repeater-delete
// element. The item is still visible. "hide" is passed a function
// as its first argument which will properly remove the item.
// "hide" allows for a confirmation step, to send a delete request
// to the server, etc. If a hide callback is not given the item
// will be deleted.
hide: function (deleteElement) {
if (confirm('Are you sure you want to delete this element?')) {
$(this).slideUp(deleteElement);
}
},
// (Optional)
// Removes the delete button from the first list item,
// defaults to false.
isFirstItemUndeletable: true
})
});
</script>
}
i want to change html in this formate like this as shown in below screenshot.

Firstly,the name format is set in jquery.repeater.js,if you want to change it,you need to change jquery.repeater.js,here is a demo worked:
1.Add the jquery.repeater.js to your project.
I copy the js to my project like this:
2.Find setIndexes in the jquery and change var newName = groupName + '[' + index + '][' + name + ']' +like this(You can also change it to other format you want):
3.change your script src from cdnjs to your own project:
<script src="~/lib/jquery-repeater/jquery.repeater.js"></script>
4.Result:

Related

show a div of image only in homepage and hide from other pages

<div class="container">
#section HeroSection{
#foreach (var category in Model.AllCategory.Where(m => m.IsFeatured).FirstOrDefault().CategoryPictures.Select(m => m.Picture).Distinct())
{
<div class="hero__item set-bg" data-setbg="/FileStore/images/#category.Url">
<div class="hero__text">
<span>FRUIT FRESH</span>
<h2>Vegetable <br />100% Organic</h2>
<p>Free Pickup and Delivery Available</p>
SHOP NOW
</div>
</div>
}
}
</div>
</div>
</div>
}
</div>
I tried to #Render the //#section HeroSection// as false in _layout page .so that it will only appear in home/index ..not in other pages!
I can think of 2 approaches.
the first one is not so practical which is making 2 different layouts, one without the div and one with it. And you can change the layout of the homepage in the razor file like this
#{Layout = "YourNewLayOut"}
The other approach which I think it's better is to use JavaScript.
you can use window.location.href to get the current url and check if it's the url of the home page you target the div and make hidden otherwise visible.
your function should look like this :
function someFunctionName() {
let div = document.querySelector("#yourDiv");
if (window.location.href === "your home page url ") {
div.style.display = "none";
} else {
div.style.display = "block or flex or what ever you're using";
}
}
and then Invoke this function on loading like this
window.onload = function() {
someFunctionName();
};

asp.net core mvc model binding with jquery repeater

I am using jquery repeater in my form to dynamically add only a part of input group to form. I did try but couldn't get inputs bind to model, I went blind.
Here my model.
public class SuggestionCreateEditViewModel
{
public Guid[] DetectionId { get; set; }
public SuggestionCreateEditRepeatedModel[] Repeated { get; set; }
}
public class SuggestionCreateEditRepeatedModel
{
public Guid To { get; set; }
public string Description { get; set; }
public DateTime Deadline { get; set; }
}
Form, I removed a lot of parts of form for brevity
<div class="col-lg-9 col-md-9 col-sm-12">
<select asp-for="DetectionId" asp-items="ViewBag.AllDetections" class="m-bootstrap-select m_selectpicker toValidate"
multiple data-actions-box="true" data-width="100%"></select>
</div>
<div class="col-lg-9 col-md-9 col-sm-12 input-group date">
<input name = "Repeated.Deadline" type="text" readonly class="form-control toValidate dtDueDate" />
</div>
<div class="col-lg-12 col-md-12 col-sm-12">
<textarea name = "Repeated.Description" class="form-control toValidate txtSuggestion" type="text" >
</textarea>
</div>
after adding a new repeated section to form and before posting it to server, if I form.serailizeArray() it returns collection like as follows (what jquery form repeater dynamically shape names I believe)
{name: "DetectionId", value: "afca1b82-0455-432e-c780-08d6ac38b012"}
{name: "[0][Repeated.To][]", value: "b1176b82-1c25-4d13-9283-df2b16735266"}
{name: "[0][Repeated.Deadline]", value: "04/04/2019"}
{name: "[0][Repeated.Description]", value: "<p>test 1</p>"}
{name: "[1][Repeated.To]", value: "188806d8-202a-4787-98a6-8dc060624d93"}
{name: "[1][Repeated.Deadline]", value: "05/04/2019"}
{name: "[1][Repeated.Description]", value: "<p>test 2</p>"}
and my controller
[HttpPost]
public IActionResult CreateSuggestion(SuggestionCreateEditViewModel model, IFormFile[] documents)
{...
controller couldn't get Repeated binded, only DetectionId is binded. How should I shape my model to get the data?
Here is a working demo for with jquery.repeater.js, pay attention to this line <div data-repeater-list="Repeated"> which will format the field like name="Repeated[0][Description]"
#model TestCore.Models.SuggestionCreateEditViewModel
#{
ViewData["Title"] = "Contact";
}
<form class="repeater" asp-action="CreateSuggestion" method="post">
<!--
The value given to the data-repeater-list attribute will be used as the
base of rewritten name attributes. In this example, the first
data-repeater-item's name attribute would become group-a[0][text-input],
and the second data-repeater-item would become group-a[1][text-input]
-->
<div data-repeater-list="Repeated">
<div data-repeater-item>
<div class="col-lg-9 col-md-9 col-sm-12">
<select asp-for="DetectionId" asp-items="ViewBag.AllDetections" class="m-bootstrap-select m_selectpicker toValidate"
multiple data-actions-box="true" data-width="100%"></select>
</div>
<div class="col-lg-12 col-md-12 col-sm-12">
<textarea name="Description" class="form-control toValidate txtSuggestion" type="text">
</textarea>
</div>
</div>
</div>
<input data-repeater-create type="button" value="Add" />
<input type="submit" value="Submit"/>
</form>
#section Scripts{
<!-- Import repeater js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.repeater/1.2.1/jquery.repeater.js"></script>
<script>
$(document).ready(function () {
$('.repeater').repeater({
// (Optional)
// start with an empty list of repeaters. Set your first (and only)
// "data-repeater-item" with style="display:none;" and pass the
// following configuration flag
initEmpty: true,
// (Optional)
// "show" is called just after an item is added. The item is hidden
// at this point. If a show callback is not given the item will
// have $(this).show() called on it.
show: function () {
$(this).slideDown();
},
// (Optional)
// "hide" is called when a user clicks on a data-repeater-delete
// element. The item is still visible. "hide" is passed a function
// as its first argument which will properly remove the item.
// "hide" allows for a confirmation step, to send a delete request
// to the server, etc. If a hide callback is not given the item
// will be deleted.
hide: function (deleteElement) {
if (confirm('Are you sure you want to delete this element?')) {
$(this).slideUp(deleteElement);
}
},
// (Optional)
// Removes the delete button from the first list item,
// defaults to false.
isFirstItemUndeletable: true
})
});
</script>
}
By the looks of things, the controller cannot bind the repeater properties back to your view model because the naming of the posted content does not match the naming in your view model (as Topher mentioned).
The DetectionId is named correctly though because the name of the property matches and its not an array.
To resolve an array we need to make sure we include the property name in the form as well as an index so that mvc model binding knows where to bind the result to.
With that, can you try changing the format of the name to:
Repeated[0].To
That should match up with your controller and correctly bind.
For more info on binding, please see this.

A simple show or hide item.text button

I have a mvc 5 project using a database.
In my project I have a Blog-page. This page is loaded using a controller.
In the page I dynamically create a list of items (blogitems) using a simple '#foreach(var item in collection).
Each item has an id (off course), a title and a description.
#foreach (var item in Model.VmBlogItems)
{
<div class="allblogs">
<div class="blogtitle">
<h4>#item.Title</h4>
</div>
<div id="allblogcontent">
#item.Description
</div>
<a id="moreless" href="">Lees meer</a>
</div>
}
My question now is how I can create a button so that when clicked on it the description is hidden or shown.
I also wrote some jquery:
<script type="text/javascript">
//when ready
$(function () {
$('#allblogcontent').hide();
$('#moreless').click(function () {
$('#allblogcontent').toggle();
});
});
</script>
However when I try this, all my items show or hide the Description.
Does anybody know how I make sure that only the Description of the selected item is shown or hidden? I just spend 6 hours reading, trying and sadly enough failing to make it work. I could use some help.
First you modify the markup so each description tag has a unique id attached to it, and the corresponding button has a reference to that id
#{
int i=0;
}
#foreach (var item in Model.VmBlogItems)
{
i++;
<div class="allblogs">
<div class="blogtitle">
<h4>#item.Title</h4>
</div>
<div id="allblogcontent#i" class='someclass'>
#item.Description
</div>
<a id="moreless" href="" data-desc-id='allblogcontent#i'>Lees meer</a>
</div>
}
Your code can figure out which is which now.
<script type="text/javascript">
//when ready
$(function () {
$('.someclass').hide();
$('#moreless').click(function () {
$('#' + $(this).attr('data-desc-id')).toggle();
});
});
</script>
A footnote
This approach will make static references between the tags, so you can move the markup around if you like. The other two solutions shown here, so far, will break if you change the order of the tags.
Just change the below section from
$('#moreless').click(function () {
$('#allblogcontent').toggle();
});
to
$('#moreless').click(function () {
$(this).siblings('#allblogcontent').toggle();
});

change div text with ajax not working

What am I doing wrong?
I try to change div text with ajax... but doesn't do anything... I guess the problem is in my controller method..
This my div
<div id="div1">
text to change
</div>
<button>change text</button>
#section scripts{
<script>
$(document).ready(function() {
$("button").click(function () {
$.ajax({
url: "/Home/ChangeText", success: function (result) {
$("#Div1").html(result);
}
});
});
});
</script>
}
This my Controller
public JsonResult ChangeText()
{
var result = "New Text";
return Json(result, JsonRequestBehavior.AllowGet);
}
Note: when is running it's enter to method 'ChangeText' but it doesn't print the result(New Text) on my view
You wrote <div id="div1"> and $("#Div1").html(result);. However div1 not equals Div1, first symbol is big (upper case). JavaScript is sensitive to upper and lower case.
The type attribute specifies the type of button. Always specify the type attribute for the <button> element. Different browsers may use different default types for the <button> element. If you want send data to controller - write type of button type="button" or type="submit".
Attribute values and descriptions:
button - The button is a clickable button
submit - The button is a submit button (submits form-data)
reset - The button is a reset button (resets the form-data to its initial values)
Try this code:
<div id="div1">
text to change
</div>
<button type="button">change text</button>
#section scripts{
<script>
$(document).ready(function() {
$("button").click(function () {
$.ajax({
url: "/Home/ChangeText", success: function (result) {
$("#div1").html(result); // Div1 != div1
}
});
});
});
</script>
}

two page layouts into one view

I would like some advice on this matter. I have a view page that will display a number of users. One view is to display users in a grid (gallery like) of their images. Second view is to display the same users but by their name in a list layout. I will have a toggle button on the page to switch between the two. What is the best way to go about it? Having two separate view pages or have a partial view of some sort?
Update Code after suggestion below
<div data-bind="template: {name:'grid-template'}"></div>
<div data-bind="template: {name:'list-template'}"></div>
<script style="float:left" type="text/html" id ="grid-template">
<section " style="width:100%; float:left">
<section id="users" data-bind="foreach: Users">
<div id="nameImage">
<figure id="content">
<img width="158" height="158" alt="Gravatar" data-bind="attr:{src: GravatarUrl}"/>
<figcaption>
<a title="Email" id="emailIcon" class="icon-envelope icon-white" data-bind="attr:{'href':'mailto:' + Email()}"></a>
<a title="Profile" id="profileIcon" class="icon-user icon-white"></a>
</figcaption>
</figure>
<p data-bind="text:Name"></p>
</div>
</section>
</section>
</script>
<script style="float:left" type="text/html" id="list-template">
<div data-bind="foreach: Users">
<div style="width:60%; float:left; margin:10px; height:58px">
<img style="float:left; margin-right:5px" width="58" height="58" alt="Gravatar" data-bind="attr:{src: GravatarUrl}"/>
<p style="height:58px; float:left; vertical-align:central" data-bind="text:Name"></p>
<a style="float:right" title="Profile" class="icon-user icon-black"></a>
<a style="float:right" title="Email" class="icon-envelope icon-black" data-bind="attr:{'href':'mailto:' + Email()}"></a>
</div>
</div>
</script>
Knockout Script File
$.views.User.UserViewModel = function (data) {
var self = this;
self.Name = ko.observable(data.Name);
self.Email = ko.observable(data.Email);
self.ContentRole = ko.observable(data.ContentRole);
self.MD5Email = ko.observable(data.MD5Email);
self.GravatarUrl = ko.computed(function () {
return 'http://www.gravatar.com/avatar/' + self.MD5Email() + '?s=300&d=identicon&r=G';
});
self.renderMode = ko.observable('grid');
self.displayTemplate = ko.computed(function () {
return self.renderMode() + '-layout-template';
});
};
Personally, I like having clean isolated small little Partial Views especially if it is going to be regular HTTP POST.
However, based on the assumptions I am making below, I think I can suggest a better implementation design.
My Assumption
You have
Index.cshtml Parent view to display a list Users.
JSON object array containing your list of Users
Based on what I see, you are using KnockoutJS.
Read the KnockoutJS Template Binding especially the "Note 5: Dynamically choosing which template is used" part.
It kind of makes it easier to do what you are doing if you are using KnockoutJS or something similar.
You simply have toggle between the two rendering templates.
<script type="text/html" id="gallery-layout-template"> ... </script>
<script type="text/html" id="listing-layout-template"> ... </script>
<div id="divOutputContainer"
data-bind="template: { name: displayTemplate, foreach: users }"></div>
<script type="text/javascript">
$(document).ready(function() {
// I am just writing out a dummy User array here.
// Render out your User Array JSON encoded using JSON.NET.
var myUsers = [
{ "id" : 1, "name": "User 1" },
{ "id" : 2, "name": "User 2" }
];
// here is your KnockoutJS View Model "class"
function MyKoViewModel(users) {
var self = this;
self.users = ko.observableArray(users);
// Toggle this renderMode observable's value
// between 'listing' and 'gallery' via your Toggle button click event handler
self.renderMode = ko.observable( 'gallery' );
self.displayTemplate = function(user) {
// this will return 'gallery-layout-template' or 'listing-layout-template'
return self.renderMode() + '-layout-template';
}
}
ko.applyBindings( new MyKoViewModel( myUsers ) );
});
</script>
So with that technique, you don't need to make an AJAX call every time to refresh the view with a different rendering template.
You have all your data that you want to display as a client-side JavaScript KnockoutJS view model.
Then, just switch the client-side rendering template using KnockoutJS.
Must more efficient :-)
NOTE
I have a feeling, you might have to use the ko.computed() for the MyKoViewModel's displayTemplate() function like this.
self.displayTemplate = ko.computed(function() {
return self.renderMode() + '-layout-template';
}

Categories