MVC4 Ajax enabled WebGrid Jquery dialog not working when paging - asp.net-mvc-4

I have an Ajax enabled WebGrid and inside this grid I have a column which generates an ActionLink, this ActionLink has a "class" added so I can catch it with jQuery and open a Dialog based on the URL passed -> this URL is a call to a method which returns a PartialView.
This is working for all buttons on first page, as soon as I change the paging the script is not called and my partial view is displayed without a layout. So the action is executed but not through javascript (where I put return false; so I don't get double postbacks).
Code:
#Code
Dim grid As New WebGrid(Model,
rowsPerPage:=10,
canSort:=True,
canPage:=True,
ajaxUpdateContainerId:="ajaxGridClientBookingWL",
fieldNamePrefix:="ajaxGridClientBookingWL",
pageFieldName:="ajaxGridClientBookingWL")
End Code
<div id="ajaxGridClientBookingWL">
<script type="text/javascript">
$(document).ready(function () {
$(".popup-button").click(function () {
//debugger;
var href = $(".popup-button").attr('href');
InitializeDialog($("#modPop"), href);
$("#modPop").dialog("open");
return false;
});
function InitializeDialog($element, href) {
$element.dialog({
autoOpen: false,
width: 400,
resizable: true,
draggable: true,
title: "Department Operation",
modal: true,
closeText: '[Zapri]',
dialogClass: 'no-close normalpopup-dialog',
closeOnEscape: true,
open: function (event, ui) {
$element.load(href);
},
close: function () {
$(this).dialog('close');
}
});
}
});
</script>
<div id="modPop">
</div>
<table cellpadding="3px">
<tr>
<td>#grid.GetHtml(tableStyle:="gridTable", headerStyle:="gridHeader", rowStyle:="gridRowStyle", alternatingRowStyle:="gridAlternatingRow",
columns:=grid.Columns(
grid.Column(header:="Datum", columnName:="DateInserted", canSort:=True, format:=##<text>#NiRISHelpers.SpanDateToShort(item.DateInserted)</text>),
grid.Column(header:="", format:=##<text>#Html.ActionLink("Izberi", "KomitentBookingWLPreveril", "Pregled", New With {.area = "Komitent", .ID = item.IDrec}, New With {.class = "popup-button"})</text>)
))</td>
</tr>
</table>
</div>
You can see I set a debugger which catches my action if on first page, it does not when I page this grid.
I put everything inside the div which is designated as ajaxUpdateContainerId, tried to put it outside of it but nothing seems to work.
The partial view is just a simple #Html.DisplayFor(....).
Edit - solution:
As per #JoeJoe87577 accepted answer below, here is my new code (the rest is the same as above only scripts and grid.column are changed):
<script type="text/javascript">
function readyTheButton() {
var href = $(".popup-button").attr('href');
InitializeDialog($("#modPop"), href);
$("#modPop").dialog("open");
return false;
}
function InitializeDialog($element, href) {
$element.dialog({
autoOpen: false,
width: 400,
resizable: true,
draggable: true,
title: "Department Operation",
modal: true,
closeText: '[Zapri]',
dialogClass: 'no-close normalpopup-dialog',
closeOnEscape: true,
open: function (event, ui) {
$element.load(href);
},
close: function () {
$(this).dialog('close');
}
});
}
</script>
And the grid.Column:
grid.Column(
header:="",
format:=##<text>#Ajax.ActionLink(
"Izberi",
"KomitentBookingWLPreveril",
"Pregled",
New With {.area = "Komitent", .ID = item.IDrec},
New AjaxOptions With {
.HttpMethod = "GET",
.InsertionMode = InsertionMode.Replace,
.UpdateTargetId = "modPop",
.OnBegin = "readyTheButton()"})</text>)

Pretty simple, the $(document).ready(function () { }); event is only fired when the page is loaded and everything is ready. But when you page the grid, all the buttons are reloaded by ajax and non of them has the click event attached.
1fst Solution:
Look in the documentation for the paging event of your grid (usually every grid has such an event), attach the click event to your actionlinks everytime the grid has changed the page.
2nd Solution:
Apply an onclick attribute to your actionlinks on the server, this onclick can lead to your InitializeDialog function.
(Edit) Addition: You could try not to use a javascript event handler, but the built in Ajax Actionlink. This will keep your page clean and you don't have to deal with javascript event handling.

Related

startup is not getting called for Dojo Custom Widget

I created a Custom Widget in Dojo
return declare("DrawTools", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
templateString: template,
layers: [],
constructor: function (featureLayerArr) {
},
postCreate: function () {
},
startup: function () {
var menu = new DropDownMenu({ style: "display: none;" });
var menuItem1 = new MenuItem({
label: "Save",
iconClass: "dijitEditorIcon dijitEditorIconSave",
onClick: function () { alert('save'); }
});
menu.addChild(menuItem1);
var menuItem2 = new MenuItem({
label: "Cut",
iconClass: "dijitEditorIcon dijitEditorIconCut",
onClick: function () { alert('cut'); }
});
menu.addChild(menuItem2);
menu.startup();
var button = new DropDownButton({
label: "hello!",
name: "programmatic2",
dropDown: menu,
id: "progButton"
}, this.drawToolsMenuNode).startup();
},
startMenu: function () {
}
});
Wdiget template is as follows
<div>
<div data-dojo-attach-point="drawToolsMenuNode"></div>
</div>
I am instantiating Widget in another Custom Widget as follows
var drawTools = new DrawTools(this.allLayersArr);
drawTools.placeAt(this.drawToolsNode);
drawTools.startMenu();
startup method for DrawTools widget is not getting called.
Need help in this regard.
Offical definition from dojo
startup():
Probably the second-most important method in the Dijit lifecycle is the startup method. This method is designed to handle processing after any DOM fragments have been actually added to the document; it is not fired until after any potential child widgets have been created and started as well. This is especially useful for composite widgets and layout widgets.
When instantiating a widget programmatically, always call the widget's startup() method after placing it in the document. It's a common error to create widgets programmatically and then forget to call startup, leaving you scratching your head as to why your widget isn't showing up properly.
So as Kirill mentioned, you need to call the startup method.
The alternative solution would be moving widget instantiation logic from ::startup() to ::postCreate(), since ::postCreate() will be called for sure.

Dojo enable button by event handler

I am working with IBM Content Navigator 2.0.3, that uses DOJO 1.8 for the GUI development. I am new in dojo, and I have to enhance one of the forms: add an event handler to the dataGrid so when the row of the grid is selected one of the buttons become enabled.
I've managed to add event handler as was advised in this issue: dojo datagrid event attach issue
but I still can't enable the button. Here is html of the form:
Add
Remove
<div class="selectedGridContainer" data-dojo-attach-point="_selectedDataGridContainer">
<div class="selectedGrid" data-dojo-attach-point="_selectedDataGrid" ></div>
</div>
The attached image describes how it looksenter image description here.enter image description here
And the js file code of postCreate function is following:
postCreate: function() {
this.inherited(arguments);
this.textDir = has("text-direction");
domClass.add(this._selectedDataGridContainer, "hasSorting");
this._renderSelectedGrid();
this.own(aspect.after(this.addUsersButton, "onClick", lang.hitch(this, function() {
var selectUserGroupDialog = new SelectUserGroupDialog({queryMode:"users", hasSorting:true, callback:lang.hitch(this, function (user) {
this._onComplete(user);
this._markDirty();
})});
selectUserGroupDialog.show(this.repository);
})));
this.own(aspect.after(this.removeUsersButton, "onClick", lang.hitch(this, function() {
if (this._selectedGrid != null) {
var selectedItems = this._selectedGrid.selection.getSelected();
if (selectedItems.length > 0) {
array.forEach(selectedItems, lang.hitch(this, function(item) {
this._selectedGrid.store.deleteItem(item);
}));
}
this._selectedGrid.selection.clear();
this._selectedGrid.update();
}
this._markDirty();
})));
// the following handler was added by me
dojo.connect(this.myGrid, 'onclick', dojo.hitch(this, function(){
console.log(" before ");
this.removeUsersButton.set('disabled', true);
console.log(" after ");
}));
},
so this.own(aspect.after(this.removeUsersButton..... works fine and worked before my interference. So it somehow accesses this.removeUsersButton and processes the event. But my handler dojo.connect(this.myGrid.... only prints console.log() before and after without enabling the Remove button. The Button has no Id, only data-dojo-attach-point. How do I enable the Remove button when the daaGrid is selected?
With this.removeUsersButton.set('disabled', true); you are setting the button to be disabled. If you want to enable it you need to set it to false.
this.removeUsersButton.set('disabled', false);

WinJS How to select a listview item on page load

I'm trying to select the first item in my listview control as soon as my nav page loads. The following code does not seem to have an effect. If i put the "selection.set(0)" code inside of a button click handler it will work fine, but it will not work as soon as the page loads which is my desired effect. Anyone have any ideas? I must be missing something very basic here!
HTML
<div id="basicListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource : ex.itemList.dataSource,
itemTemplate: select('#mediumListIconTextTemplate'),
layout : {type: WinJS.UI.ListLayout},
selectionMode: 'single',
tapBehavior: 'directSelect'
}">
</div>
JS
(function () {
"use strict";
var _lv = null;
WinJS.UI.Pages.define("/pages/page2/page2.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
_lv = document.getElementById("basicListView").winControl;
// This should select the first item in the listview though it seems to have no effect.
_lv.selection.set(0);
},
});
})();
I think your problem is that the list is not populated when you try to access it.
Try to put this code in your ready event so you will know when the list is ready:
ready: function (element, options) {
var listView = element.querySelector(".itemslist").winControl;
listView .onloadingstatechanged = function (args) {
if (args.srcElement === listView .element && listView .loadingState === "complete") {
//and here you set your item
_lv = document.getElementById("basicListView").winControl;
_lv.selection.set(0);
}
};
}

Header and Footer keep showing up with modal pop up window

I just want to show basic HTML without the header and footer of my main page when using a modal window.
How can one do that in MVC3/4?
Here is an example of what is happening...
Not sure why it is doing that.
This is a basic jquery modal window call
$(function () {
//$('a.tempDlg').live("click", function (event) { loadDialog(this, event, '#edit-set'); });
//$('a.AddPatDlg').live("click", function(event) {loadDialog(this, event, '#addPat');});
//debugger;
$('a.addEncounter').live("click", function (event) { loadDialog(this, event, '#DisplayUniqueEncounters'); });
$('a.SearchEncounter').live("click", function (event) { loadDialog(this, event, '#searchEncounter'); });
//$("#sID").click(function (event) { loadDialogByClick(this, event, '#searchEncounter'); });
});
function loadDialog(tag, event, target) {
//debugger;
event.preventDefault();
var $loading = $('<img src="<%=Url.Content("~/Images/ajax-loader.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: 1200
, modal: true
, minHeight: 550
, show: 'fade'
, hide: 'fade'
});
$dialog.dialog('open');
};
I have done this before without including the header and footer, and I forget how it was done? I must be missing a step.
You can also set the Layout = null at the top of the page
That is correct... I want to give nemesv credit for this answer, but he didn't answer the question. So I will just say that he was right. You need to return a partialView(), not just a regular view... Returning a regular view always gets all of the other MVC markup. Thanks...

Dojo Tooltip only shows after first mousover event

I'm using dojo's event delegation to connect a Tooltip widget to dynamically generated dom nodes.
The Dojo site explains event delegation this way:
"The idea behind event delegation is that instead of attaching a
listener to an event on each individual node of interest, you attach a
single listener to a node at a higher level, which will check the
target of events it catches to see whether they bubbled from an actual
node of interest; if so, the handler's logic will be performed."
Following is my code implementation. It works beautifully ... EXCEPT, the tooltip only shows AFTER the first mouse over event. When I first mouseover the node, the event fires perfectly, but the tooltip doesn't render. It will only show the consequent mouseover events. On the first mouseover event, I can watch the Firebug console and see the xhr.get go to the database and get the correct data. If I comment out the tooltip and throw in a simple alert(), it works the first time.
Any suggestions on how to get the Tooltip to show on the first mouseover event? Thanks in advance!
<div class="col_section" id="my_groups">
<div class="col_section_label">My Groups</div>
<ul>
<?php
foreach($myGroups as $grp) {
echo '<li><a class="myGroupLink" id="grp'.$grp['grp_id'].'">'.$grp['name'].'</a></li>';
}
?>
</ul>
</div>
<script>
require(["dojo/on",
"dojo/dom",
"dijit/Tooltip",
"dojo/_base/xhr",
"ready!"], function(on, dom, Tooltip, xhr) {
// Get Group ToolTip
var myObject = {
id: "myObject",
onMouseover: function(evt){
var grp_id = this.id;
var content = '';
xhr.get({
url: "getGrpInfo.php",
handleAs: "json",
content: {
grp_id: grp_id,
content: "tooltip"
},
load: function(info) {
if(info == 0) {
content = '<div class="grpToolTip">';
content += ' Information about this group is confidential';
content += '</div>';
} else {
content = '<div class="grpToolTip">';
content += ' <img src="../ajax/getimg.php?id='+info.logo_id+'" />';
content += ' <div style="text-align:center">'+info.name+'</div>';
content += '</div>';
}
new Tooltip({
connectId: [grp_id],
label: content
});
},
error: function() {}
});
}
};
var div = dom.byId("my_groups");
on(div,".myGroupLink:mouseover",myObject.onMouseover);
});
</script>
Your Tooltip does not show on the first onmouseover because it does not exist at the moment the onmouseover event was fired.
dijit/Tooltip instances manage theirs mouse events themselves, so you do not have to manage onmouseover/onmouseout and you probably did so because you do not want to preload data or you want to load data every time the tooltip is about to show.
Beside dijit/Tooltip instances you can use Tooltip.show(innerHTML, aroundNode, position) and Tooltip.hide(aroundNode) to display tooltips, but in that case you will have to manage mouse events yourself, which is what you need, because from the UX perspective, you do not want to show single tooltip, you want to:
Show a tooltip indicating information is being loaded.
Then either:
display XHR loaded information if a user still hover over the node
cancel XHR and hide tooltip on mouseout
Here is working example: http://jsfiddle.net/phusick/3hmds/
require([
"dojo/dom",
"dojo/on",
"dojo/_base/xhr",
"dijit/Tooltip",
"dojo/domReady!"
], function(
dom,
on,
xhr,
Tooltip
) {
on(dom.byId("groups"), ".group-link:mouseover", function(e) {
var target = e.target;
Tooltip.show("Loading...", target);
var def = xhr.post({
url: "/echo/html/",
content: { html: target.textContent},
failOk: true,
load: function(data) {
Tooltip._masterTT.xhr = null;
Tooltip._masterTT.containerNode.innerHTML = data;
Tooltip._masterTT.domNode.width = "auto";
},
error: function(e) {
if (e.dojoType != "cancel") {
console.error(e);
}
}
});
Tooltip._masterTT.xhr = def;
});
on(dom.byId("groups"), ".group-link:mouseout", function(e) {
var target = e.target;
Tooltip.hide(target);
if (Tooltip._masterTT.xhr) {
Tooltip._masterTT.xhr.cancel();
}
});
});​
As usual, I was over-thinking the problem, focusing on event registration rather than on simply creating the tooltips when the page loads. So, it's really stupidly simple:
query for the nodes
iterate through them and create the tooltips pointing to each node.
var myGroupsList = query("a.myGroupLink"); // query nodes based on class
array.forEach(myGroupsList,function(entry,i){ // iterate through
var grp_id = entry.id;
var content = '';
xhr.get({ // get data via xhr.get
url: "getGrpInfo.php",
handleAs: "json",
content: {
grp_id: grp_id,
content: "tooltip"
},
load: function(info) {
if(info == 0) {
content = '<div class="grpToolTip">';
content += ' Information about this group is confidential';
content += '</div>';
} else {
content = '<div class="grpToolTip">';
content += ' <img src="../ajax/getimg.php?id='+info.logo_id+'" />';
content += ' <div style="text-align:center">'+info.name+'</div>';
content += '</div>';
}
new Tooltip({ // create tooltip
connectId: [entry.id],
label: content
});
},
error: function() {}
});
});