link to another controller with hot towel and durandal - asp.net-mvc-4

I am developing an mvc4 app with multiple spa's.
I am using the hot towel template for my spa.
What I want to do is have a anchor link within my views for a spa go to the index action for another controller, so my users can exit one spa and open another. Not all actions will start a spa some are regular mvc style pages.
I have put code like like the following in my spa html pages:
Navigate to another controller
This will change the url in the browser but always reloads the default html page for the spa. If I hit the refresh button in the browser then if will go to the proper page.
I have been able to put a target on the anchor tag of _parent or _top like:
Navigate to another controller
and it will navigate to the new controller page.
I believe it is something in the durandal framework that is preventing the spa from navigating to the second controller, but since I am just starting to work with this, I am stumped as what I need to change. I think there should be a better way than using the target in the anchor tag, or is that the best option.

I hope that I have understood you correctly. I believe this behaviour is caused my Sammy.js (which the durandal router is currently based on). The default behaviour of Sammy is to hijack all links and process them as regards to the SPA itself.
I didn't like this behaviour for the website I am working on and needed links to other MVC web pages to be possible from within the SPA. What I really wanted is for regular links to just work and hash links to be interpreted as a link to another view within the SPA. So '/controller/action' would go to another web page and '#moduleId' would go to another durandal V/VM.
I found this Sammy option that works for me and set it in my main.js
// This stops Sammy from hijacking regular links
Sammy.Application.prototype.disable_push_state = true;

Related

Reason SPA pages are refreshing?

Just finished learning Vuejs and after visiting a few websites that use Vuejs like;
a) https://coderstape.com
b) https://www.thenetninja.co.uk
c) https://laracasts.com
I noticed that by navigating around the websites we by clicking on navbar links and some other links then the pages refresh and I haven't been able to find out the reason online. Could someone kindly explain what's happening in that? Doesn't it go against the purpose of SPA?
For example the last site you specified: https://laracasts.com.
On its main page there is a white button "BROWSE COURSES". If you open Chrome DevTools panel(look at the picture with explanations), go to tab "Networks" (1) and then click on this white button, you can see GET request to "series?curated" (2). If you open its details, you can see that as response, new page is received in the form of an HTML code (3), not JSON for example, as is usually the case in SPA.
Also, if you look at what programming language is used on this site, for example, using service https://whatcms.org/?s=laracasts.com, you can see that this is a PHP, namely Laravel.
From all this, I can make the assumption that they use Vue.js only partially, maybe in several components, but the site navigation itself is presented in the form of traditional static pages, which is why the page reloads.
Also, for example, if you take a look at this website https://www.spendesk.com/, you can see that they use Vue.js+Nuxt.js, as well as Node.js, as indicated by service whatcms.org, and if you try to navigate to various pages on this site, you will see no page loading. I can say that this site is a true SPA in the form in which you mean it.
I heard that you can do a SPA with a Laravel backend, but I think that's another story.

Additional pages with SPA

I'm creating a SPA app using Durandal and I would like to include a credit card payment facility. The guys that I'm looking at requires you to give return URLs to success, cancel and a view other pages, is that possible?
To me it would be breaking the 'single page' part of SPA, but is it possible? Could I do it all in a window?
Disclaimer: I don't know Durandal, but you would solve this in an SPA using either "hashbang URIs" or actually re-serving the SPA in your webserver for the requested return URI and adjusting the content using the same technique as hangbash URIs but using history.pushstate/history.popstate instead, see here: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history
A more general article from Google is available here that covers the same principle: https://developers.google.com/webmasters/ajax-crawling/
This "works" because SPAs are SPAs only in that the browser requests a new HTML document from the server once (or in your case, twice), the SPA should still be updating the history and address-bar state of the UA as the user navigates the application, just as though it were a regular multi-page application.
A great example of this is GitHub's source navigator: Try here ( https://github.com/angular/angular.js ) and navigate the repository, observe that the contents of the file-listing change as does the address bar, but your browser doesn't reload the whole page... yet if you copy+paste the (modified) address bar address into a new browser window, you get the same page back.
I looked into doing credit card processing from a SPA and the best option I had found was Stripe. They supply a javascript file that looks like it would work, I never implemented it on my project due to time constraints so I can't confirm that it works but it looked very promising.
IFRAMEs are quite good for this sort of thing. You can use jQuery to hook an event handler to the page load event and this will tell you when the other end has responded. Load the 3rd party page into the IFRAME and serve response pages on the URLs you provide to the service provider. As mentioned by others you can use routes to identify the response pages. The IFRAME will stop the round-tripping from mucking up your application state and in fact it is possible to put script in your response pages that dot-notates its merry way up the DOM and into your app.

ViewStateException - Validation of viewstate MAC failed - Sitefinity ASP.NET MVC with Jquery Mobile

I am getting this error most of the time when I submit my form. I am using Sitefinity 6.2 with ASP.NET MVC 4.0 and JQuery Mobile.
As I have Sitefinity in Hybred mode I am using the #Html.BeginFormSitefinity() command to create the form. On the Controller I have my action with the [HttpPost] attribute. The code always hits my default action on the controller with no problem. No matter what I put in the form when I submit I only get an error message on the page...never hits the HttpPost action.
I've looked around and there are many pages with fixes for the MAC failed issue, but none are working for me. I have a machine key in the web.config and I am NOT going to set enableViewStateMac to false as that is a security hole.
OK I tried working with both of the below solutions but they are both really bad. Here is what I am doing now, which is still not great, but I have Sitefinity, MVC, and JQuery Mobile all on the same page and forms are not giving me View State Exceptions anymore.
First thing is that adding data-ajax="false" is not enough, for this to work you need to disable Ajax before JQuery Mobile starts. So, to do this you need to add in this script BEFORE the JQuery Mobile File loads but after the JQuery file loads.
$(document).bind("mobileinit", function () { $.mobile.ajaxEnabled = false; });
After doing this I then do not use the Sitefinity Begin Form, I just JQuery to change the form on the main page to have the correct action.
<script>
$("#aspnetForm").attr("action", "Home/Login");
</script>
Together this means that there is a complete page load for each page change, and form posts use the form declared in my WebForms Master Page.
-Old Answer -
Actually...what I have below is not working. What I am
currently doing is really ugly but is usually working.
As long as the user enters the site from the home page then the home
page is the Jquery Mobile first page. The view state errors that I
was getting was because it saw the current page as the first page and
the form submit was to the active page. What if the controller for
the home page was just set to handle ALL HTTPPost calls? I have
removed the #Html.BeginFormSitefinity() from all the views with forms
and am just using the form on my top level masterpage. Then I add in
code on the view to change the action of this form to point to the
main page controller. ex
<script>
$("#aspnetForm").attr("action", "Home/Login");
</script>
Once I made this change the forms are not throwing view state
exceptions...as long as the home page is the Jquery Mobile first page.
If the user comes in from a different page then all is scrambled.
Don't have an answer for that yet.
Really Old Answer -
OK, think I have found it. I read somewhere, lost the link now, a
list of issues that can cause the error message. One of them is the
form being submitted from a different page.
I looked at the error message I was getting with Fiddler and noticed
that the Referer was my home page but the URL of the form post was the
URL for the page with my form. In stead of browsing through my site
to the page with the form I typed the URL in the address bar. I tried
submitting my form again and now it works!
So, this is an issue of Sitefinity and JQuery Mobile fighting it out.
When asp.net MVC is run in Hybred mode in Sitefinity it is actually
run in a Web.Forms master page that contains a form. When you use the
#Html.BeginFormSitefinity() to add a form to the view it is actually
just adding a div and then using AJAX to submit the form on the
Web.Forms master page.
JQuery Mobile loads up the first page that you visit, but later pages
are just injected into the existing page. So, there are multiple
data-role="page" divs loaded up in the DOM, inside of the Sitefinity
Web.Forms Master Page.
This all together is causing the form to post with the URL of the
active data-role="page" but the server sees that it is being refered
from the original page I loaded up. So, if I went to the page with
the form first all would work, start at any other page it does not
work.
Now that I know this I can put in data-ajax="false" on the link to the
page with the form and all looks to be working. This will cause
JQuery Mobile to not inject the target page into the current page but
will load all fresh with the target.
data-ajax="false" is the answer!

WinJS Share Target Redirect

In WinJS is it possible to redirect a page once it has been activated by using the share charm?
So my target page is /pages/target/target.html. In the .js I want to do something like;
WinJS.Navigation.navigate("/pages/anotherpage/anotherpage.html");
It doesn't seem to raise an error but it's not navigating away from the target page.
I want to redirect pages based on user input.
This is similar to another question:
How to navigate between different html pages in Windows 8 Metro application using javascript?
However, if you actually are performing a page navigation (e.g. window.location changes), then you're going to have the challenge that the activation info with the share stuff will not be available; your script context is torn down on a page navigation, so you won't be able to hold onto it easily.

Running multiple extjs4 apps on a liferay portal page

I'm using liferay portal for a website. All of my portlets are based on Extjs4 MVC framework. The problem is that when I add multiple Extjs4 based portlets to a page one of them won't load. I experimented with the app.js files of the apps. and found out that when I added the initialization code to one of the portlets all of them starts running.
for example following code works,
Ext.Loader.setPath('Ext', '/loc-treeview-portlet/loc-treeview/ext-4.0/src');
//loader path for the first app
Ext.Loader.setPath('LocTree', '/loc-treeview-portlet/loc-treeview/app');
//loader path for the second app
Ext.Loader.setPath('ServiceTree', '/service-layer-portlet/service-treeview/app');
// Instantiate the apps which I have created by extending Ext.app.Application
Ext.create('LocTree.app.LocTreeApplication');
Ext.create('ServiceTree.app.ServiceTreeApplication');
But I can't do this in the actual portal because it's not known in advance which of the extjs4 apps will be in the page. Does any body have any idea of how to get these apps to work independently?
Perhaps you can extract the Application definition into the page template that way you know there is only one App launch event. Then each portlet is essentially a view with its own controller. You will need to call init() manually on the controllers though.
The problem seems to be that document 'ready' event in ExtJS4 only initializes one app(portlet) in a given page. So what I did was to wrap all the code app.js file in an AUI().ready() call.
AUI().ready(function(){
// all app.js code here
});