I don't have so much experience using AJAX in a MVC application, in fact is my first facing. Please check the below image and note the rectangles.
The image is just an example that I took from internet.
The biggest rectangle is a partial view in my application and I have to render it when the user press Continue or Continuar button. The application should replace the current view for another without refresh the page.
This is the code which I'm testing, note first that I'm passing the first element of a list, but when the user press the button, render the view with the next element index = 2.
public ActionResult DoTest()
{
if (!Request.IsAjaxRequest())
{ }
List<Worksheet> worksheets = new List<Worksheet>()
{
new Worksheet("Hoja 1", ...),
new Worksheet("Hoja 2", ...)
};
return View(worksheets[0]);
}
Can orient me a little bit to know how to implement this feature? I just know that I need to use Ajax.
Have a look through the tutorials and examples here. There's plenty of other material around on the web with information on this subject.
There are many different ways you can achieve this. One way would be to write a custom paging Helper (HtmlHelper) that accepts new content upon the post event. You can view all about Helpers here : Custom HTML Helpers
Another way could be to use partial page rendering to achieve the partial page update upon post event.
If I was you I would combine a partial view with a jquery function to update the content. You can view some help on that here: Change dive content with Jquery
Related
I have an app with four main pages, switched through a tab bar (no "back" button).
One page has a lot of content (ScrollView) and takes quite a few seconds until it's rendered. I handle that by showing a "loading" overlay while the work is done. But for that specific page I'd like to keep the view alive, so that when the user switches to another page and comes back later, the page is ready without loading everything again.
I'm not sure how to do that in MvvmCross, though.
I did read the documentation and from what I understood the View Presenter would be the right way to do it, since the docs say:
"Another kind of presentation changes your app can request through
hints includes clearing / modifying the BackStack, changing a root
while maintaining the existent views, … possibilities are really
endless. Once again your app is king here!"
I guess I would need to create a custom MvxPresentationHint for that, but I don't quite get it :(
How or rather where would I access and store/load the View?
I'm generally still quite unfamiliar with MvvmCross (how it works under the hood) and especially customization of Mvx classes, even though I've been using it for a while.
Any explanation and preferably code examples beyond what's written in the documentation would be extremely appreciated!
It isn't meaningful to attempt to "store" a view in MVVM. The XF view is a representation of what will be created with native (e.g. "Android" or "iOS") widgets. Creating and measuring/laying out those native widgets is what is slow. MVVM View Presenter won't speed up that logic.
Instead of "store", you need "keep alive":
For a ContentPage called MyPage, when you create it, store it in a static variable. Then re-use that variable. If you never need more than one of these, you can store it in the class itself.
Modify the "code behind", MyPage.xaml.cs:
public partial class MyPage : ContentPage
{
// Singleton Pattern.
private static MyPage _it;
public static MyPage It {
get {
if (_it == null)
_it = new MyPage();
return _it;
}
}
// "private", because calling this directly defeats the purpose. Instead, use `MyPage.It`.
private MyPage()
{
InitializeComponent();
}
}
To create it, whereever you would put:
new MyPage()
instead put this:
MyPage.It
For instance, you might do PushAsync(MyPage.It);
This will always return the SAME INSTANCE of MyPage. So once it has been created, it keeps its state.
IMPORTANT: Note that the constructor is only called ONCE. Any code that needs to be done each time the page appears, put in override .. OnAppearing() method.
LIMITATION: Views "expect" to be part of the visual hierarchy when they are manipulated. If you attempt to alter the page or its view model while it is not on the screen, you may encounter problems. Those are beyond the scope of this answer - create a new StackOverflow question with the details of any problem you encounter.
So I would like to be able to have a print button for entries in our database so users can print an entry via a print friendly "form".
My thought was to create a separate page, add labels and have those labels pull the relevant information.
I know I can add the open widget information via this code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.TestPrint);
But I'm running into a few problems:
I can't get the page to open in a new window. Is this possible?
window.open(app.pages.TestPrint);
Just gives me a blank page. Does the browser lose the widget source once the new window opens?
I can't get the print option (either onClick or onDataLoad) to print JUST the image (or widget). I run
window.print();
And it includes headers + scroll bars. Do I need to be running a client side script instead?
Any help would be appreciated. Thank you!
To get exactly what you'd want you'd have to do a lot of work.
Here is my suggested, simpler answer:
Don't open up a new tab. If you use showPage like you mention, and provide a "back" button on the page to go back to where you were, you'll get pretty much everything you need. If you don't want the back to show up when you print, then you can setVisibility(false) on the button before you print, then print, then setVisibility(true).
I'll give a quick summary of how you could do this with a new tab, but it's pretty involved so I can't go into details without trying it myself. The basic idea, is you want to open the page with a full URL, just like a user was navigating to it.
You can use #TestPrint to indicate which page you want to load. You also need the URL of your application, which as far as I can remember is only available in a server-side script using the Apps Script method: ScriptApp.getService().getUrl(). On top of this, you'll probably need to pass in the key so that your page knows what data to load.
So given this, you need to assemble a url by calling a server script, then appending the key property to it. In the end you want a url something like:
https://www.script.google.com/yourappaddress#TestPage?key=keyOfYourModel.
Then on TestPage you need to read the key, and load data for that key. (You can read the key using google.script.url).
Alternatively, I think there are some tricks you can play by opening a blank window and then writing directly to its DOM, but I've never tried that, and since Apps Script runs inside an iframe I'm not sure if it's possible. If I get a chance I'll play with it and update this answer, but for your own reference you could look here: create html page and print to new tab in javascript
I'm imagining something like that, except that your page an write it's html content. Something like:
var winPrint = window.open('', '_blank', 'left=0,top=0,width=800,height=600,toolbar=0,scrollbars=0,status=0');
winPrint.document.write(app.pages.TestPage.getElement().innerHTML);
winPrint.document.close();
winPrint.focus();
winPrint.print();
winPrint.close();
Hope one of those three options helps :)
So here is what I ended up doing. It isn't elegant, but it works.
I added a Print Button to a Page Fragment that pops up when a user edits a database entry.
Database Edit Button code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showDialog(app.pageFragments.FragmentName);
That Print Button goes to a different (full) Page and closes the Fragment.
Print Button Code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.ModelName_Print);
app.closeDialog();
I made sure to make the new Print Page was small enough so that Chrome fits it properly into a 8.5 x 11" page (728x975).
I then created a Panel that fills the page and populated the page with Labels
#datasource.item.FieldName
I then put the following into the onDataLoad for the Panel
window.print();
So now when the user presses the Print Button in the Fragment they are taken to this new page and after the data loads they automatically get a print dialog.
The only downside is that after printing the user has to use a back button I added to return to the database page.
1.
As far as I know, you cannot combine window.open with app.pages.*, because
window.open would require url parameter at least, while app.pages.* is essentially an internal routing mechanism provided by App Maker, and it returns page object back, suitable for for switching between pages, or opening dialogs.
2.
You would probably need to style your page first, so like it includes things you would like to have printed out. To do so please use #media print
ex: We have a button on the page and would like to hide it from print page
#media print {
.app-NewPage-Button1 {
display : none;
}
}
Hope it helps.
1. Here is how it is done, in a pop up window, without messing up the current page (client script):
function print(widget, title){
var content=widget.getElement().innerHTML;
var win = window.open('', 'printWindow', 'height=600,width=800');
win.document.write('<head><title>'+title+'/title></head>');
win.document.write('<body>'+content+'</body>');
win.document.close();
win.focus();
win.print();
win.close();
}
and the onclick handler for the button is:
print(widget.root.descendants.PageFragment1, 'test');
In this example, PageFragment1 is a page fragment on the current page, hidden by adding a style with namehidden with definition .hidden{display:none;} (this is different than visible which in App Maker seems to remove the item from the DOM). Works perfectly...
2. You cannot open pages from the app in another tab. In principle something like this would do it:
var w=window.parent.parent;
w.open(w.location.protocol+'//'+w.location.host+w.location.pathname+'#PrintPage', '_blank');
But since the app is running in frame nested two deep from the launching page, and with a different origin, you will not be able to access the url that you need (the above code results in a cross origin frame access error). So you would have to hard code the URL, which changes at deployment, so it gets ugly very fast. Not that you want to anyway, the load time of an app should discourage you from wanting to do that anyway.
I have two questions, both related to the same view: so there is view called ProductDetails which shows the details of a product.
Each product can have the status:
Available - in this case, two button are available "edit" and "remove"(which will change the status of the product to "Not available" but will not remove it from DB)
Not available - in this case, the page displays the product but no options to edit or remove are
visible.
The controller ProductsController has an action Details that shows that view.
The problem is that I don't know how to implement the two buttons (Edit and Remove) because:
Edit sends to another action method (Edit which display another view) <- this works
Remove should do (IMO) a post on the current page. In the post action, the status of the product is changed and the view is shown again.
I want both button to look like links. If I put a form for remove, then it will be displayed as a button. I would like to avoid making the button look like a link with css. Or... at least I want to use the same HTML element for both 'buttons'.
This is more an issue of displaying the elements so I have added the CSS tag to your question as some alternative answers may rely on this.
Personally I think trying to make a button look like a text link would be quite awkward, even once you turn off the border and background you have issues with lining up the text etc.
I'd say you have 2 "simple" options.
Firstly you could make the delete not post a delete request but link to a delete confirmation page (or bring up a JS modal window with your delete form and button).
Secondly you could make them both look like buttons, while you requested that it looks like a link I figured that the main point was consistency in UI than the link look specifically. You could use JQueryUI and invoke .button() on both elements, invoking JQueryUI for 1 feature is a bit overkill but it's a quick change, of course you could replicate the same idea of styling the link like the buttons but would have to spend time dealing with browser CSS issues.
the Remove link should post to the Remove action, which should in turn (after validation and DB update) redirect to the details action.
public ActionResult Details(int productId)
{
// Your current action method
return View(model);
}
public ActionResult Remove(int productId)
{
// Validate productId
// Update DB
return RedirectToAction("Details", new { productId = productId } );
}
You easily can solve your link vs button problem by using a GET instead of a POST. Don't be blinded by best practices.
Or you can use a Remove link that executes a one-liner Javascript function that posts the form:
Remove
My requirement is to have database based help system for asp.net website, as shown in the image below. i have searched web but could not find even remotely related solution.
DNN Help System http://img3.imageshack.us/img3/6720/dnnhelpimage20091125.jpg
You could assign each help item a unique ID (perhaps GUID to make it easier to generate by the developer enabling help for that item).
Clicking on the link opens a dialog, tooltip, new window, whatever. Just have the UI load the help text by ID from the database.
To make this easier to implement in the UI, there are a few ways. Perhaps you can create a jQuery client-side behavior.
your HTML would look something like:
<span class="help" id="#{unique-id-here}">Admin</admin>
and you could have jQuery on DOM load:
$(function() {
var help = $(".help");
help.prepend("<img src=\"path/to/images/help.png\" />");
help.click(function() {
//do something with this.id; open a popup, a title bar, whatever.
}
});
We did it on our site by doing the following:
We have a HelpTopics database with a HelpTopicId and HelpTopicText
We create an aspx page that displays the HelpTopicText based on the HelptopicId passed in the querystring.
We set up a css class for the A tag that displays the link to the help with the question mark image.
We created a UserControl named TitleandHelp that contained a link to the page mentioned in step 2 and the style for the link set to step 3 above: The usercontrol has a public rpoperty for the title and one for the topicID (We called it HelpContext).
We add the usercontrol to the aspx page where appropriate
<uc2:titleandhelp ID="titleandhelp1" runat="server" HelpContext="4" PageTitle="Forgot Password" />
it may sound like a lot of work, but really it only takes a half hour or so to do all of the setup. The rest of the work lies in populating the table and dragging the usercontrol onto the pages where appropriate.
It is possible to add multiple reCAPTCHAS in one form? I tried doing so, even giving the multiple reCAPTCHAS different IDs, but when I load the page in the browser, only one of them is shown.
Is this by design? I need the two reCAPTCHAS because one is for Login, and the other one is for the Register form, which will be shown on the same page.
Thanks!
WT
Only one Cpatcha is supported in a page at any time. What you can do is use AJAX and lod captcha after the form is loaded.
This might of some help.
After a quick google search, it appears that it's not currently possible. One suggestion I saw was to pop up a modal recaptcha just as the user submits the form. ondemandcaptcha for Ruby.
I was initially lead by this thread to believe there is no simple answer, but after digging through the Recaptcha ajax library I can tell you this isn't true! TLDR, working jsfiddle: http://jsfiddle.net/Vanit/Qu6kn/
It's possible to overwrite the Recaptcha callbacks to do whatever you want with the challenge. You don't even need a proxy div because with the overwrites the DOM code won't execute. Call Recaptcha.reload() whenever you want to trigger the callbacks again.
function doSomething(challenge){
$(':input[name=recaptcha_challenge_field]').val(challenge);
$('img.recaptcha').attr('src', '//www.google.com/recaptcha/api/image?c='+challenge);
}
//Called on Recaptcha.reload()
Recaptcha.finish_reload = function(challenge,b,c){
doSomething(challenge);
}
//Called on page load
Recaptcha.challenge_callback = function(){
doSomething(RecaptchaState.challenge)
}
Recaptcha.create("YOUR_PUBLIC_KEY");
It is now possible to do this easily with explicit recaptcha creation. See my answer here:
How do I show multiple recaptchas on a single page?
It's not too difficult to load each Recaptcha only when needed using the Recaptcha AJAX API, see my post here:
How do I show multiple recaptchas on a single page?
the captcha has an img element #recaptcha_challenge_image element , so after you set the recaptcha in one div say "regCaptch",get that img src attr
,set your other captcha div html to the old one html and then set the #recaptcha_challenge_image src to the src you get , here is a working example
var reCaptcha_src = $('#recaptcha_challenge_image').attr('src');
$('#texo').html($('#regCaptch').html());
$('#recaptcha_challenge_image').attr('src',reCaptcha_src);