Populate a Kendo dialog with partial view - kendo-ui

I have a kendo dialog which I want to populate with a partial view but it's sort of not working.
I want to populate the dialog with the click of a button, so here's my code so far
<div id="dialog"></div>
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
var dialog = $("#dialog");
console.log("objId", dataItem.OBJECTID1)
$.ajax({
url: '#Url.Action("SavePartial", "SettlementContract")',
data: {
id: dataItem.OBJECTID1
},
success: function (result) {
if (result != null) {
dialog.html(result);
dialog.data("kendoDialog").open();
}
}
});
}
I tried removing the if condition inside the success, just in case but it's not working either. It returns the partial view, but not inside the kendo dialog, the dialog doesn't even open. What am I doing wrong?

We do this in our application and this is how we have set it up (I updated it to use your controller/actions/ids) - this is using the ASP.NET Core MVC wrappers:
#(Html.Kendo().Window()
.Name("dialog")
.Content("loading...")
.Draggable()
.Actions(actions => actions.Maximize().Close())
.Resizable()
.Modal(true)
.Visible(false)
.Events(e => e.Refresh("onDialogWindowRefresh"))
)
<script>
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
let win = $("#dialog").data("kendoWindow");
win.refresh({
url: "/SettlementContract/SavePartial/",
data: {
id: dataItem.OBJECTID1
}
});
}
function onDialogWindowRefresh(e) {
e.sender.center().open();
}
</script>

Related

how to load a partial view inside an anchor tag which has been generated via Ajax

I have a form with a dropdownlist. When selecting an option, I make an ajax call to dynamically add a list of links in the view. When I click on one of the links, I want to update the existing page with a partial view returned by the PostListSubCategory() method.
Currently, clicking on one of the links does a redirect and shows the partial view in a new page. How can I update the the existing page?
<script language="javascript" type="text/javascript">
function GetSubCategory(_categoryId) {
var procemessage = "<a='0'> Please wait...</a>";
$("#SubCategoryID").html(procemessage).show();
var url = "/Posts/GetSubCategoryById/";
$.ajax({
url: url,
data: { categoryid: _categoryId },
cache: false,
type: "POST",
success: function (data) {
var markup = "";
for (var x = 0; x < data.length; x++) {
var num = data[x].Text;
markup += "<a href='/posts/postlistsubcategory?subcategoryid=" + data[x].Text + "'>" + data[x].Text + "</a><br />";
// markup += "<a href=" + Url.Action("postlistsubcategory", new { subcategoryid = num });
}
$("#SubCategoryID").html(markup).show();
},
error: function (reponse) {
alert("error : " + reponse);
}
});
$.ajax({
url: "/Posts/PostListCategory",
data: { categoryid: _categoryId },
cache: false,
type: "POST",
success: function (data) {
$("#postList").html(data).show();
},
error: function (reponse) {
alert("error : " + reponse);
}
});
}
</script>
#using (Html.BeginForm())
{
#Html.ListBoxFor(m => m.CategoryModel, new SelectList(Model.CategoryModel, "CategoryId", "Name"), new { #id = "ddlcategory", #style = "width:200px;", #onchange = "javascript:GetSubCategory(this.value);" })
<br />
<br />
<div id="SubCategoryID" name="SubCategoryID" style="width: 200px"></div>
<br /><br />
}
In the controller
public PartialViewResult PostListSubCategory(string subcategoryid)
{
if (subcategoryid == null)
{
return PartialView(db.Posts.ToList());
}
return PartialView("PostList", db.Posts.Include(i => i.SubCategory).Where(p => p.SubCategory.Name == subcategoryid));
}
You currently dyamically generating links with an href attribute so clicking on them will do a redirect. You need to handle the click event of those links using event delegation and then use ajax to update the existing DOM. There a some other bad practices in your code and I suggest you use the following
#using (Html.BeginForm())
{
// no need to override the id attribute and use Unobtrusive Javascript (don't pollute markup with behavior)
#Html.ListBoxFor(m => m.CategoryModel, new SelectList(Model.CategoryModel,"CategoryId", "Name"))
}
<div id="SubCategoryID"></div> // no point adding a name attribute
<div id="postList"></div>
var subcategories = $('#SubCategoryID');
$('#CategoryModel').change(function() {
var url = '#Url.Action("GetSubCategoryById", "Posts")'; // don't hard code url's
var category = $(this).val();
subcategories.empty(); // clear any existing links
$.post(url, { categoryid: category }, function(data) { // this could be a GET?
$.each(data, function(index, item) {
subcategories.append($('<a></a>').text(item).attr('href','#').addClass('subcategory')); // see note below
});
});
});
Note: Since your ajax only needs one property to generate the links (the value to display in the link), then your GetSubCategoryById() should be returning IEnumerable<string> not a collection of complex objects (you current code suggest your returning other data which you never use). If you do need to return a collection of objects, then change the above to use .text(item.Text). The above code will generate
.....
for each item you return. Then add an additional script to handle the .click() event of the links (since the links are dynamically added, you need event delegation using the .on() method)
var posts = $('#postList');
$('#SubCategoryID').on('click', '.subcategory', function() {
var url = '#Url.Action("postlistsubcategory", "posts")';
var subcategory = $(this).text();
posts.load(url, { subcategoryid: subcategory });
});

partial view loaded by Ajax do not render code after #RenderBody

I have an application developped in C# / MVC4.
It has a top menu and bottom menu.
A partial view is loaded in the main view when I click on a link (banana or apple) using ajax:
#Ajax.ActionLink("Connection", "Details", "SourceConfiguration", new { id = "4505F2DE-91A2-496B-9BCB-BD1D3C2C3FB1" }, new AjaxOptions { UpdateTargetId = "result" })
When the link is clicked, it should also modify the layout in order to display different top and bottom menus: (similar to Windows Azure bottom menu which display contextual action depending on where you are).
How I can I achieve that? (see below for what has been tested).
What has been tried so far:
The default _layout.cshtml contains
#RenderBody()
#RenderSection("Bottom", false)
the home/index.cshtml contains this code:
#section Bottom
{
the code to create the bottom menu
[...]
}
=> This is correctly rendered.
Here comes the problem:
each page in the views contain the Bottom section.
The bottom section is not displayed in pages called by partial view (ex: views/apple/index.cshtml).
What's the best way when I click on Apple to display the partial view and to display a specific top and bottom bar?
Got it:
in HomeController:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MenuLayout(string name)
{
return PartialView("_MenuLayout", null);
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MenuBottomLayout(string name)
{
return PartialView("_MenuBottomLayout", null);
}
In _Layout.cshtml
<div class="navcontainer">
</div>
<div class="">
#RenderBody()
</div>
<div class="navcontainerbottom">
</div>
And javascript code:
<script type="text/javascript">
var menuLoaded = false;
$(document).ready(function () {
if($('.navcontainer')[0].innerHTML.trim() == "")
{
$.ajax({
url: "#Url.Content("~/Home/MenuLayout")",
type: "GET",
success: function (response, status, xhr)
{
var nvContainer = $('.navcontainer');
nvContainer.html(response);
menuLoaded = true;
},
error: function (XMLHttpRequest, textStatus, errorThrown)
{
var nvContainer = $('.navcontainer');
nvContainer.html(errorThrown);
}
});
}
if($('.navcontainerbottom')[0].innerHTML.trim() == "")
{
$.ajax({
url: "#Url.Content("~/Home/MenuBottomLayout")",
type: "GET",
success: function (response, status, xhr)
{
var nvContainer = $('.navcontainerbottom');
nvContainer.html(response);
menuLoaded = true;
},
error: function (XMLHttpRequest, textStatus, errorThrown)
{
var nvContainer = $('.navcontainerbottom');
nvContainer.html(errorThrown);
}
});
}
});
</script>
And finally _MenuLayout.cshtml and MenuBottomLayout.cshtml contain the code that create the top and bottom menu.

subpage loaded through ajax is killing jquery functionality

I'm working on a site, http://teneo.telegraphbranding.com/, and I am hoping to load the pages via ajax so that the sidebar and its animation remain consistent.
When the 'About' link is clicked I need it to load about2.php via a jquery ajax function. But I'm not having any luck. When I can get the page to load via ajax it kills all the jquery functionality on the page. From what I've read I think I need to call the jquery upon successful completion of the ajax call.
I've tried everything it seems and can't get it work. What I need is about2.php to load when the link is clicked and the jquery to dynamically size the divs, like it does on the homepage.
I tried this, but it won't even load the page:
//Dropdown
$(document).ready(function () {
var dropDown = $('.dropdown');
$('h3.about').on('click', function() {
dropDown.slideDown('fast', function() {
var url = 'about2.php'
$.get(url, function(data) {
//anything in this block runs after the ajax call
var missionWrap = $('#mission-wrap');
var w = $(window);
w.on('load resize',function() {
missionWrap.css({ width:w.width(), height:w.height()});
});
var missionContent = $('#mission-content');
var w = $(window);
w.on('load resize',function() {
missionContent.css({ width:w.width() - 205 });
});
});
});
});
});
And then this loads the page, but kills all the jQuery associated with it:
var dropDown = $('.dropdown');
$('h3.about').on('click', function() {
dropDown.slideDown('fast', function() {
$('#index-wrap').load('/about2.php');
});
});
Thank you very much.
I also tried this and it just broke everything:
$(document).ready(function () {
var dropDown = $('.dropdown');
$('h3.about').on('click', function () {
dropDown.slideDown('fast', function () {
$.ajax({
type: 'GET',
url: 'about2.php',
success: function () {
var missionWrap = $('#mission-wrap');
var w = $(window);
w.on('load resize', function () {
missionWrap.css({
width: w.width(),
height: w.height()
});
});
var missionContent = $('#mission-content');
var w = $(window);
w.on('load resize', function () {
missionContent.css({
width: w.width() - 205
});
});
};
});
});
});
});
This should work.
function resize_me () {
var w = $(window);
var missionWrap = $('#mission-wrap');
var missionContent = $('#mission-content');
missionWrap.css({ width:w.width(), height:w.height()});
missionContent.css({ width:w.width() - 205 });
}
//Dropdown
$(document).ready(function () {
$(window).on('load resize', function () {
resize_me();
});
var dropDown = $('.dropdown');
$('h3.about').on('click', function() {
dropDown.slideDown('fast', function() {
var url = 'about2.php'
$.get(url, function(data) {
resize_me();
});
});
});
}
I believe that the problem was that the load event that you were attaching to the window object was not being triggered by the successful load of the $.get.
This is a rough outline of how to structure your application to handle this correctly.
Assuming your HTML looks something like this:
<html>
...
<div id="index-wrap">
<!-- this is the reloadable part -->
...
</div>
...
</html>
You need to refactor all the jQuery enhancements to the elements inside #index-wrap to be in a function you can call after a reload:
function enhance(root) {
$('#some-button-or-whatever', root).on('click', ...);
}
(I.e. look up all the elements under the root element that was loaded using AJAX.)
You need to call this function when the page is first loaded, as well as after the AJAX call in the completion callback:
$('#index-wrap').load('/foo.php', function() {
enhance(this);
});
You can also potentially get rid of some of this using delegated ("live") events, but it's best to hit the jQuery documentation on how those work.
As for events bound to window or DOM elements which aren't loaded dynamically, you shouldn't need to rebind them at all based on which subpage is loaded, just check which of your elements loaded is in a handler that you set up once:
$(window).on('load resize', function() {
var $missionContent = $('#missionContent');
if ($missionContent.length) {
$missionContent.css(...);
}
});

Trigger sort method from an event in Backbone.js

I have a Backbone.js project which uses a comparator function defined in the collection. It sorts items when the page is refreshed, but I am trying to get it to sort when a button is clicked instead of on page refresh. Here is my code:
var Thing = Backbone.Model.extend({
defaults: {
title: 'blank',
rank: ''
}
});
var ThingView = Backbone.View.extend({
className: 'thingClass',
template: _.template('<b><button id="remove">X</button> <b><button id="edit">Edit</button> <%= title %> Rank:<%= rank %></b>'),
editTemplate: _.template('<input class="name" value="<%= name %>" /><button id="save">Save</button>'),
events: {
"click #remove": "deleteItem",
"click #edit": "editItem",
"click #save": "saveItem",
},
deleteItem: function () {
console.log('deleted');
this.model.destroy();
this.remove();
},
editItem: function () {
console.log('editing');
this.$el.html(this.editTemplate(this.model.toJSON()));
},
saveItem: function () {
console.log('saved');
editTitle = $('input.name').val();
console.log(editTitle);
this.model.save({
title: editTitle
});
this.$el.html(this.template(this.model.toJSON()));
},
render: function () {
var attributes = this.model.toJSON();
//console.log (attributes);
this.$el.append(this.template(attributes));
return this;
}
});
var ThingsList = Backbone.Collection.extend({
model: Thing,
localStorage: new Store("store-name"),
comparator: function(thing) {
return thing.get('rank');
},
});
var thingsList = new ThingsList;
var ThingsListView = Backbone.View.extend({
el: $('body'),
events: {
'click #add': 'insertItem',
'click #sort': 'sortItems',
},
initialize: function () {
thingsList.fetch();
thingsList.toJSON();
this.render();
this.collection.on("add", this.renderThing, this);
this.collection.on("reset", this.clearRender, this);
},
insertItem: function (e) {
newTitle = $('#new-item').val();
newRank = $('#rank').val();
newThing = new Thing({
title: newTitle,
rank: newRank
});
this.collection.add(newThing);
newThing.save();
console.log(this.collection.length);
},
sortItems: function (e) {
console.log('clicked sort button');
this.collection.sort();
this.$el.detach('.item');
},
render: function () {
_.each(this.collection.models, function (items) {
this.renderThing(items);
}, this);
},
renderThing: function (items) {
var thingView = new ThingView({
model: items
});
this.$el.append(thingView.render().el);
},
clearRender: function () {
console.log('clear render called')
_.each(this.collection.models, function (items) {
//this.remove();
this.$el.remove(".thingClass")
this.renderThing(items);
}, this);
},
test: function (items) {
console.log('test worked');
},
});
var thingsListView = new ThingsListView({
collection: thingsList
});
Are you sure your collection isn't resorting itself? keep in mind that the order of the models in the collection won't change the order of how they appear on the page if they are already rendered.
I'm guessing that what you are trying to do is resort the items that have already been rendered, to do so you would need re-render your collection. If you are going to do so I would recommend that you cache your views and on a sort detach the associated element from the DOM and reattach them in the correct order.
As an example
var ThingsListView = Backbone.View.extend({
_views: {},
initialize: function () {
this.collection.bind('add', this.add, this);
this.collection.bind('reset', this.render, this); //sort triggers a reset
},
add: function (thing) {
var view = new ThingView({model: thing});
this._views[thing.cid] = view; //use client id of model as key for the views cache
this.$el.append(view.render().el);
},
render: function() {
$('li, this.$el).detach(); //detach so that bound events aren't lost
_.each(this.collection.models, function(thing) {
this.$el.append(this.views[thing.cid].el); //get view from cache
},this);
},
sort: function() {
this.collection.sort();
}
}
})
(a couple of differences from my example code and yours I'm assuming here that the collection view has a 'el' referring to a container 'ul', I also don't show how your triggering the sort (basically something like thingListView.sort();)
Edit: It might not be so obvious from the example code I posted, so I should have mentioned to begin with what #Deeptechtons said that when you sort a collection it triggers a reset event
Edit2: If your not interested in caching your views, then the easiest way to remove your current views would probablly be to add a class to the rendered div
var ThingView = Backbone.View.extend({
className: 'thingClass',
//rest of your thingViewCode
Then in your clearRender method just add $(".thingClass", this.$el).remove(); to the beginning of the method.

jQuery UI Dialog Validation

I know this is a common problem. I've been looking at the various solutions proposed on this site and elsewhere but cannot hit upon something that works in my situation.
Here is my script:
$(function () {
$('a.editPersonLink').live("click", function (event) {
loadDialog(this, event, '#personList');
$.validator.unobtrusive.parse('#editPersonContainer');
});
$(".deleteButton").live("click", function(e) {
e.preventDefault();
var $btn = $(this);
var $msg = $(this).attr("title");
confirmDelete($msg,
function() {
deleteRow($btn, $target);
});
});
});
function loadDialog(tag, event, target) {
event.preventDefault();
var $loading = $('<img src="../../Content/images/ajaxLoading.gif" alt="loading" class="ui-loading-icon">');
var $url = $(tag).attr('href');
var $title = $(tag).attr('title');
var $dialog = $('<div></div>');
$dialog.empty();
$dialog
.append($loading)
.load($url)
.dialog({
autoOpen: false
,title: $title
,width: 800
,modal: true
,minHeight: 200
,show: 'slide'
,hide: 'clip'
});
$dialog.dialog( "option", "buttons", {
"Save": function () {
var dlg = $(this);
$.ajax({
url: $url,
type: 'POST',
data: $("#formData").serialize(),
success: function (response) {
$(target).html(response);
dlg.dialog('close');
dlg.empty();
$("#ajaxResult").hide().html('Record saved').fadeIn(300, function () {
var e = this;
setTimeout(function () { $(e).fadeOut(400); }, 2500);
});
},
error: function (xhr) {
if (xhr.status == 400)
dlg.html(xhr.responseText, xhr.status); /* display validation errors in edit dialog */
else
displayError(xhr.responseText, xhr.status); /* display other errors in separate dialog */
}
});
},
"Cancel": function() {
$(this).dialog("close");
$(this).empty();
}
});
$dialog.dialog('open');
};
Right up near the top I am trying to cause the form to recognise the validation from the partial view on the dialog via the statement:
$.validator.unobtrusive.parse('#editPersonContainer');
editPersonContainer is the name of the div containing the data in the partial view loaded into the dialog.
The bottom line is that the validation is not recognised. Am I making the call to validator.unobtrusive.parse in the wrong place, or am I missing something else here?
I ended up changing my script to use the techniques described here
Validation now works on my jQuery UI dialogs.
Hi I came up to your question as I was looking for the same.
I include this before the ajax call to validate on client side:
if (ModelState.IsValid) {}
I make an article with the full project on
Validation client/Server JqueryUI Dialog

Resources