Get SelectedItem in Dropdownlist without FormMethod.Post - asp.net-mvc-4

I have a dropdownlist that is bound to a list in my model. Model.list_IDs
The current page is an "editing" page where a user would inherently change a property of the model by using the dropdownlist.
#Html.DropDownListFor(model => Model.ID, Model.list_IDs, new { style = "width:250px" })
The items within the dropdownlist are not intuitive, so I would like to provide a button, that when clicked, retrieves additional information via a stored procedure (called from the controller via a method called GetDetails)
The button is created through an action link, and I plan to display a partial view (like a focused pop up window) that shows the additional information once the button is clicked.
#Html.ActionLink(" ", "GetDetails", new { id = Model.ID.ToString() }, new { #class = "lnkMagnify16", title = "View Details" })
Obviously Model.ID.ToString() is incorrect, because it will only send the model's current ID, rather than the ID currently selected in the dropdownlist.
How can I change Model.ID.ToString() to represent the dropdownlist's current selected item?
I know there is a way to do this using FormMethod.Post (Get selected item in DropDownList ASP.NET MVC) but I do not want to reload the page with a submit button. I'd also like to avoid "third party" approaches like JavaScript if possible.

JavaScript is not a "third party" approach, and it's also the only way to accomplish what you want here. Whether by a standard form post or via AJAX (JavaScript), you must make a new request to the server to get the new information you want.
Now, since all you're specifically after is a way to dynamically update the the Model.ID value in the link, you can do that without AJAX or a form post, but you still must use JavaScript, since all dynamic behavior client-side originates from JavaScript. Basically, you'd need to bind to the change event of the dropdown and alter the href property of your link.
document.getElementById('ID').addEventListener('change', function () {
var selectedId = this.options[this.selectedIndex].value;
document.getElementById('AwesomeLink').href = // alter `href` with `selectedId`
});
However, that link is still going to change the whole view if the user clicks it. If you truly want the user to stay on the page, then you'll need to fetch the response of that link using AJAX and then either add it to the page somehow, whether that be directly or via a modal popup (which will required yet even further JavaScript to achieve). Also, it's not clear how the Model.ID value ends up in the URL, i.e. whether it's part of the path (/some/url/{id}/) or as a query string param (/some/url/?id={id}). If it's the former, I'd recommend switching to the latter, as it will make it much easier to build your URL client-side.
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function (response) {
// add response.responseText to the DOM
});
xhr.open("GET", "/some/url/?id=" + selectedId);
xhr.send();

Related

Web browser control, modal window/popup to STAY INSIDE web browser control for Visual Studio 2015/Visual Basic 2015

this is the first time I'm posting a question here; I have searched and searched and searched here and other places and I cannot seem to get any results. I'm using VISUAL BASIC 2015 in Visual Studio 2015. QUESTION: I need to have a modal window/popup from a particular website remain INSIDE the web browser control/window on my form (WebBrowser1); when a particular link is clicked, the modal window/popup jumps out of the form and directly to the user on their screen. I have to keep this popup inside because there are other links to be clicked on that popup, but if it jumps out of the web browser control, no code will work since it's outside WebBrowser1. What I have found is code for older versions, and not 2015; if anything I can even add WebBrowser2 to have the popups/modal windows appear there if possible, just as long as I can code them to keep clicking inside the form. PLEASE HELP! THANK YOU!
window.open (and a click on <a target="_blank"> etc) can be handled via the NewWindow2 event. Hans already pointed out how to do that in comments. NewWindow3 works too, but need at least Windows XP SP2.
As for window.showModalDialog, it is a bit tricky. IE has IDispatchEx (wrapped as IExpando in .Net) implemented on scripting objects so you replace the methods and properties with your own implementation. But window.showModalDialog shows a dialog that has arguments and return values, you need to override those properties in the modal dialog you create too. The code looks roughly like tis:
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//skip events from frames
if(WebBrowserReadyState.Complete!=webBrowser1.ReadyState) return;
if(FindLoginFormOnPage()) {DoLogin();return;}
if(IsWelcomePage()){NavigateToPage1();return;}
if(IsPage1()){SubmitFormOnPage1();return;}
if(IsPage1FormResult()){
var document=webBrowser1.Document.DomDocument as mshtml.ITMLDocument2;
var expando =(IExpando)document.parentWindow;
expando.RemoveMember(expando.GetMethod("showModalDialog"
,BindingFlags.Instance | BindingFlags.Public);
expando.AddMethod("showModalDialog"
,new ShowModalDialogDelegate(this.MyShowModalDialog));
}
......
}
object MyShowModalDialog(string url, object varArgIn, object options)
{
using(FromMyShowModalDialog myShowModalDialog
=new MyShowModalDialog())
{
myShowModalDialog.StartupUrl=url;
myShowModalDialog.DialogArguments=varArgIn;
//omit the code to parse options
//and set dialog height/width/topleft location etc
if(myShowModalDialog.ShowDialog()==DialogResult.OK)
{
//do something on the return value before passing to the scripts
......
return myShowModalDialog.ReturnValue;
}
return null;
}
}
and in the Load event handler of MyShowModalDialog you call something like webBrowser1.Navigate to show the page requested by the parent page.
Now you need to pass the arguments to the webbrowser control on the new form. Do the same as above but replace another property this time.
expando.RemoveProperty("dialogArguments");
expando.AddProperty("dialogArguments")
.SetValue(expando,this.DialogArguments);
This will let the web page access the value passed from MyShowModalDialog and stored in this.DialogArguments.
The earliest you can access the DOM is in webBrowser1_DocumentCompleted. By that time the scipts on the page that read window.dialogArguments are probably already executed and got nothing. After overriding window.dialogArguments, you need to study the script on the page to find out how to revert that. for example, if the page has
<head>
<script>
var oMyObject = window.dialogArguments;
var sFirstName = oMyObject.firstName;
var sLastName = oMyObject.lastName;
</script>
...
<span style="color: 00ff7f">
<script>
document.write(sFirstName);
</script>
</span>
you need to change the values of sFirstName and sLastName then change the innerText property of the span, probably identify via its relationship with a named div or table cell. You can write the necessary changes in a script and call it via HtmlDocument.InvokeScript.
If the page returns a value to its parent, you need to pass it on to your parent form too. Override window.returnValue so when the script writes to window.returnValue it writes to a variable you provided
......
expando.RemoveProperty("returnValue");
expando.AddProperty("returnValue").SetValue(expando,this.ReturnValue);

how to open multiple windows from the controller in asp.net MVC

How to open multiple windows from the controller?
For example, I have a controller that gets all the clients and for each client I want that his info is displayed in a different window or tab.
Is that possible using asp.net MVC 4?
I've done this exact thing, it was based on a button click which would fire multiple windows based on the parameters. Here's what you could do. Your controller would be like this...
[HttpPost]
public ActionResult CopyOpportunitySave(CopyOpportunityViewModel model)
{
ViewModel model = new ViewModel();
foreach (var url in "List object that contains URLS")
{
model.ClientURLs.Add(url);
}
return View("CopyOpportunity", model);
}
So now your Model class will have a property like
public List<string> ClientURLs{get; set;}
which is populated by all the URLs you will need to do a window.Open.
and Now in your view you can say
#foreach (var u in ViewModel.ClientURLs)
{
<script>
window.open(u);
</script>
}
just as long as the script inside the foreach loop is getting executed, it will work
This won't be possible by just using native MVC 4. However, one could think of some work-arounds which might resemble your requirements. For starters, is it necessary to actually open a 'browser tab' per client, or could this also be a tab page per client in one single HTML-document. If the latter is an option, you could take a look at different 'tab' controls being available in HTML.
If your really want a new browser window per client, my hint would be to return the list of possible clients to one HTML page and then use scripting in that HTML page to open a popup window for each client. For each popup / client an additional request needs to be send to the server.
Just make the link (<a></a>) that opens the client information have a target = "_blank":
John Smith
If you are using Html helpers it could be like this:
#Html.ActionLink("John Smith", "Details", "Clients", new {id = 1}, new { target = "_blank"})
This will open a new browser tab with the page you need.

Dynamic menu button items in TinyMCE

I have a custom menubutton in my tinyMCE editor that uses specific HTML elements elsewhere on the page as the menu items. I use a jQuery selector to get the list of elements and then add one each as a menu item:
c.onRenderMenu.add(function(c,m) {
m.add({ title: 'Pick One:', 'class': 'mceMenuItemTitle' }).setDisabled(1);
$('span[data-menuitem]').each(function() {
var val = $(this).html();
m.add({
title: $(this).attr("data-menuitem"),
onclick: function () { tinyMCE.activeEditor.execCommand('mceInsertContent', false, val) }
});
});
});
My problem is that this only happens once when the button is first clicked and the menu is first rendered. The HTML elements on the current page will change occasionally based on user clicks and some AJAX, so I need this selector code to run each time the menu is rendered to make sure the menu is fully up-to-date. Is that possible?
Failing that, is it possible to dynamically update the control from the end of my AJAX call elsewhere in the page? I'm not sure how to access the menu item and to update it. Something using tinyMCE.activeEditor.controlManager...?
Thanks!
I found a solution to this problem, though I'm not sure it's the best path.
It doesn't look like I can make tinyMCE re-render the menu, so instead I've added some code at the end of my AJAX call: after it has updated the DOM then it manually updates the tinymce drop menu.
The menu object is accessible using:
tinyMCE.activeEditor.controlManager.get('editor_mybutton_menu')
where mybutton is the name of my custom control. My quick-and-dirty solution is to call removeAll() on this menu object (to remove all the current menu items) and then to re-execute my selector code to find the matching elements in the (new) DOM and to add the menu items back based on the new state.
It seems to work just fine, though tweaks & ideas are always welcome!

DojoX Mobile ListItem load HTML via AJAX and then remove from DOM

Let's say in a view I have a DojoX Mobile ListItem that is pulling an HTML view fragment into the DOM via AJAX and then transitioning to that view. Assume this is all working fine.
Now, I go back to the initial view that had that ListItem on it and click some other button that destroys that view node from the DOM. If I now click on that ListItem that previously loaded that view node into the DOM (which has now been removed), it will try to transition to a view that doesn't exist. It doesn't know that it has been removed.
Is there some type of way to tell a ListItem that it needs to fetch the HTML again because what was previously fetched no longer exists? I am not seeing anything about doing this in any documentation anywhere. I don't think a code sample is really necessary here, but I can provide a minimal one if necessary.
I went a different route and left the view exist in the DOM, and simply made a function that clears all sensitive data out of the view.
Okay, in this case, i guess you could hook the onShow function of your ListItem container(or any other onchange event). Create a listener for said handle to evaluate if your item needs reloading. Following is under the assumtion that it is the item.onclick contents showing - and not the label of your item which contains these informations
Or better yet, do all this during initialization so that your ListItem container will be an extended with custom onClick code.
Seems simple but may introduce some quirks, where/when/if you programatically change to this item, however here goes:
function checkItem() {
// figure out if DOM is present and if it should be
if( isLoggedIn() ) {
this.getChildren().forEach(function(listitem) {
if( dojo.query("#ID_TO_LOOK_FOR", listitem.domNode).length == 0 ) {
// this references the listItem, refresh contents.
// Note: this expects the listitem to be stateful, have no testing environment at time being but it should be
listitem.set("url", listitem.url);
}
});
}
}
Preferably, set this in your construct of the container for your ListItems
var listItemParent = new dojox.mobile.RoundRectList({
onShow : checkItem,
...
});
Or create listener
var listItemParent = dijit.byId('itemRegistryId');
// override onClick - calling inheritance chain once done
dojo.connect(listItemParent, "onClick", listItemParent, checkItem);

Check if Dojo's content pane is available or not

I have a requirement where I need to create a dojox.layout.ContentPane programmatically.
function constructContentPane(methodToBeCalled){
var testCntPane=new dojox.layout.ContentPane({
href: "some url",
executeScripts: true,
cleanContent: true,
onDownloadEnd: methodToBeCalled
}).placeAt("testContentPaneId");
testCntPane.startup();
}
This places the content pane inside testContentPaneId and calls methodToBeCalled method once the content pane is created.
I have two questions.
How do I check if the content pane is already created or not? I tried to check using the code below
if(dijit.byId("testContentPaneId") == undefined) {
//then don't create again
}
But this did not work. Each time it creates the content pane with the id dojox_layout_ContentPane_0. The last digit gets incremented each time.
Is this the right way to pass the onComplete method as argument? This is how I invoke this
constructContentPane(thisMethodWillBeCalled);
Is there any better way to do this? How do I invoke that method? I tried using eval(methodToBeCalled), but that did not work.
When you use the placeAt() method then the widget will be placed as a child to the specified dom node. I think in your case you should pass the dom directly to the constructor of the content pane.
Try doing like this instead:
var testCntPane=new dojox.layout.ContentPane({
href:"some url",
executeScripts:true,
cleanContent:true,
onDownloadEnd:methodToBeCalled
}, "testContentPaneId");
This will also make sure that the id of the content pane is testContentPaneId