ajaxSubmit does not reload page after first request (in CakePHP) - cakephp

I'm creating a CMS which has a page edit section. I'm trying to create a Preview function. It works fine on the first attempt, but if you then change some text and preview again, the preview is the old version. It also appears very quickly. It's as if the ajaxSubmit function doesn't bother reloading the page.
I tried to get round this by changing the url each time (by adding on a timestamp to the end), but this made no difference. I'm using jquery, cakePHP and fck editor.
Here's what I have:
<script type="text/javascript">
$('#page_modal').jqm();
$('#preview_btn').click(function(e){
// Get current page content from fck iframe
var oEditor = FCKeditorAPI.GetInstance('PageContent');
var newcontent = oEditor.GetData();
$('#PageContent').html(newcontent);
// Submit form via Ajax
var d=new Date();
var t=d.getTime();
var thisurl = '/admin/pages/preview/' + t.toString();
$('#ajaxForm').ajaxSubmit({
url: thisurl,
error: function(XMLHttpRequest, textStatus, errorThrown){
alert(textStatus);
},
success: function(responseText){
$('#page_modal').jqmShow().find('#page_modal_content').html(responseText);
}
});
e.preventDefault();
});
</script>
As I said, it works fine first time, but then on subsequent calls the content is not updated. Can anyone suggest anything?

Try marking the view (/admin/pages/preview) with no cache. In the actual view put:
<cake:nocache>
// your view content here
</cake:nocache>
It may be that the view is being cached by cake so it does not update with subsequent calls.
http://book.cakephp.org/view/347/Marking-Non-Cached-Content-in-Views

Related

Implementing google custom search in angularjs

I am trying to implement google custom search in an angular js website.
When I click on the search button it does not display me anything, but the url is updated to the url.
I have followed the steps mentioned in the documentation by google.
I am not sure what I am doing wrong?
My search bar is located on the home page as -
<gcse:searchbox-only enableAutoComplete="true" resultsUrl="#/searchresult" lr="lang_en" queryParameterName="search"></gcse:searchbox-only>
my search result has -
<gcse:searchresults-only lr="lang_en"></gcse:searchresults-only>
Any input is much appreciated.
Thanks,
You may have more than one problem happening at the same time...
1. Query Parameter mismatch
Your searchresults-only does not match the queryParameterName specified on gcse:searchbox-only.
Index.html
<gcse:searchresults-only queryParameterName="search"></gcse:searchresults-only>
Search.html
<gcse:searchresults-only queryParameterName="search"></gcse:searchresults-only>
2. Angular.js is blocking the flow of Google CSE
Under normal circumstances, Google Search Element will trigger an HTTP GET with the search parameter. However, since you are dealing with a one-page application, you may not see the query parameter. If that suspicion is true when you target resultsUrl="#/searchresult", then you have two options:
Force a HTTP GET on resultsUrl="http://YOURWEBSITE/searchresult". You may have to match routes, or something along those lines in order to catch the REST request (Ember.js is really easy to do so, but I haven't done in Angular.js yet.)
Use JQuery alongside Angular.js to get the input from the user on Index.html and manually trigger a search on search.html. How would you do it? For the index.html you would do something like below and for the results you would implement something like I answered in another post.
Index.html
<div>GSC SEARCH BUTTON HOOK: <strong><div id="search_button_hook">NOT ACTIVATED.</div></strong></div>
<div>GSC SEARCH TEXT: <strong><div id="search_text_hook"></div></strong></div>
<gcse:search ></gcse:search>
Index.js
//Hook a callback into the rendered Google Search. From my understanding, this is possible because the outermost rendered div has id of "___gcse_0".
window.__gcse = {
callback: googleCSELoaded
};
//When it renders, their initial customized function cseLoaded() is triggered which adds more hooks. I added comments to what each one does:
function googleCSELoaded() {
$(".gsc-search-button").click(function() {
$("#search_button_hook").text('HOOK ACTIVATED');
});
$("#gsc-i-id1").keydown(function(e) {
if (e.which == 13) {
$("#enter_keyboard_hook").text('HOOK ACTIVATED');
}
else{
$("#search_text_hook").text($("#gsc-i-id1").val());
}
});
}
(function() {
var cx = '001386805071419863133:cb1vfab8b4y';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
I have a live version of the index.html code, but I don't make promises that will be permanently live since it is hosted in my NDSU FTP.

IE only anglure http request cache / MVC issue

I have some code that loads a list from a MVC controller.
I load the data with
$scope.loadData = function () {
$scope.promise = myhttp = $http.get("forms");
myhttp.success(function (response) {
$scope.rows = response;
This works fine, the data loads and I can see the data on my html page.
But, if I reload with code, eg I just run $scope.loadData again, it fails in IE.
Works in Chrome, FF
Fails in IE and Spartan (Tested on non windows 10 same issue)
The headers look like
Cache-Control: private, s-maxage=0
The MVC controller has the authorise attribute hence the s-maxage=0, this prevents the proxy from caching.
I have tried
$scope.promise = myhttp = $http.get("forms");
When I fiddle, i dont see the request going to the server but the code does get fired.
If I nav to a new page and nav back it does reload fresh data as you would expect. It just when the reload is done with $http
Thanks
EDIT
Post works, eg
$scope.promise = myhttp = $http.post("forms");

Backbone model's fetch doesn't work when the page initially loads but on second attempt works fine

In my backbone project I am trying to fetch a model based on some search criteria submitted by the users from a form. In submit handler, I am trying to fetch the model by passing search criteria's via data option (following is the code).
var productType=$("#productType").val();
var customerId=$("#customerId").val();
var stateSelected=$("#selectedState").val();
var srbStatus=$("#stateReportingStatus").val();
var dateType=$("#dateType").val();
var fromDate=$("#fromDate").val();
var toDate=$("#toDate").val();
var billTypeInd=$("#billTypeIndicator").val();
var dataElement=$("#dataElement").val();
var ediFileName=$("#ediFileName").val();
var ediBillName=$("#ediBillNumber").val();
var billId=$("#billId").val();
var claimantFirstName=$("#claimantFirstName").val();
var claimantLastName=$("#claimantLastName").val();
var insurerName=$("#insurerName").val();
var insurerFEIN=$("#insurerFEIN").val();
var insurerZip=$("#insurerZIP").val();
var dashboardSearchResultModel= new dashboardSearchResult();
var dashboardSearchResultModel= new dashboardSearchResult();
dashboardSearchResultModel.fetch({
data:{
productType: productType,
customerId: customerId,
state:stateSelected,
srbStatus:srbStatus,
dateType:dateType,
fromDate:fromDate,
toDate:toDate,
billTypeInd:billTypeInd,
dataElement:dataElement,
ediFileName:ediFileName,
ediBillName:ediBillName,
billId:billId,
claimantFirstName:claimantFirstName,
claimantLastName:claimantLastName,
insurerName:insurerName,
insurerFEIN:insurerFEIN,
insurerZip:insurerZip
},
wait:true,
success: function(dashboardSearchResultModel)
{
alert("This is what we get for result"+JSON.stringify(dashboardSearchResultModel));
$('#dashboardResultArea').html(self.dashboardResultTemplate({results:dashboardSearchResultModel.get("results")}));
},
error: function (model, xhr, options) {
alert("Error: An error occurred while trying to fetch the dashboardSearchResultModel");
alert("Error got model"+JSON.stringify(model));
alert("options:"+JSON.stringify(options));
alert("xhr:"+JSON.stringify(xhr));
}
});
Initially when the page loads after providing the search criteria's if I click submit the fetch doesn't work and goes to the error handler. After that when I submit the from second time the fetch works and retrieves data from the backend server. Any idea what is wrong? Thanks in advance.
When error callback is called, it is because your XHTMLRequest to the server returned a error (HTTP status code). So, there is where your problem resides.
Who starts this code? As the erros does not occur on a second attempt, I would suggest that you area callind $('#id').val() when the DOM is not ready. This way you are sending null values to the server, and that's causing the error you are receiving.
To solve your problem, assure you DOM is ready when executing this script.
See if your request is leaving the browser and reaching the server (i.e., cross-domain request fail with status 0, not reaching the server).
And, if it is, debug your server-side, as it does not seem to be an client-side problem.
So after trying many things I finally decided to try $.ajax call rather the fetch method. This is what I came up with
$.ajax({
type: "GET",
url: "rest/dashboardResult",
dataTyp: 'json',
data: {
productType: productType,
customerId: customerId,
state:stateSelected,
srbStatus:srbStatus,
dateType:dateType,
fromDate:fromDate,
toDate:toDate,
billTypeInd:billTypeInd,
dataElement:dataElement,
ediFileName:ediFileName,
ediBillName:ediBillName,
billId:billId,
claimantFirstName:claimantFirstName,
claimantLastName:claimantLastName,
insurerName:insurerName,
insurerFEIN:insurerFEIN,
insurerZip:insurerZip
}
})
.done(function(response) {
alert( "Result is: " + response);
});
This works without any problem from the get go. Now my question is how to bind the response to the backbone model?
Finally I figured out what was wrong. The call was inside a submit click handler, and $.ajax call or fetch is asynchronous. So by the time the call got reply from the server default action of submit click already took place (which is to reload the page). So by the time success or .done got called the whole page was reloaded. So I put event.preventDefault() at the beginning of handler method and let the handler receive the call back from the server and display it at the template. Thanks everyone for your time.

Angular js way to download file and show loading screen using the $resource

I am using Angular js to show loading screen. It works for all the REST services call except REST service to download the file. I understand why it is not working because for download I am not making any service call using $resource; instead of that I am using normal approach to download the file therefore Angular js code doesn't have any control on start/finish the service request. I tried to use $resource to hit this REST service however I am getting the data from this service and in this case loading screen was working fine however not sure how to use this data to display to user to download in angular way. Following are required details. Please help.
Approach 1 using iframe approach:
/*Download file */
scope.downloadFile = function (fileId) {
//Show loading screen. (Somehow it is not working)
scope.loadingProjectFiles=true;
var fileDownloadURL = "/api/files/" + fileId + "/download";
downloadURL(fileDownloadURL);
//Hide loading screen
scope.loadingProjectFiles=false;
};
var $idown; // Keep it outside of the function, so it's initialized once.
var downloadURL = function (url) {
if ($idown) {
$idown.attr('src', url);
} else {
$idown = $('<iframe>', { id: 'idown', src: url }).hide().appendTo('body');
}
};
Approach 2 using $resource (Not sure how to display data on screen to download)
/*Download file */
scope.downloadFile = function (fileId) {
//Show loading screen (Here loading screen works).
scope.loadingProjectFiles=true;
//File download object
var fileDownloadObj = new DownloadFile();
//Make server call to create new File
fileDownloadObj.$get({ fileid: fileid }, function (response) {
//Q? How to use the response data to display on UI as download popup
//Hide loading screen
scope.loadingProjectFiles=false;
});
};
This is the correct pattern with the $resource service:
scope.downloadFile = function (fileId) {
//Show loading screen (Here loading screen works).
scope.loadingProjectFiles=true;
var FileResource = $resource('/api/files/:idParam', {idParam:'#id'});
//Make server call to retrieve a file
var yourFile = FileResource.$get({ id: fileId }, function () {
//Now (inside this callback) the response data is loaded inside the yourFile variable
//I know it's an ugly pattern but that's what $resource is about...
DoSomethingWithYourFile(yourFile);
//Hide loading screen
scope.loadingProjectFiles=false;
});
};
I agree with you that this is a weird pattern and is different of other APIs where the downloaded data is assigned to a parameter in a callback function, hence your confusion.
Pay attention to the names and the cases of the parameters, and look that there're two mappings involved here, one between the caller to the $resource object and the object itself, and another between this object and the url that it contructs for downloading the actual data.
Here are some idea's for the second approach, you could present the user with a link after the download has happened:
With a "data url". Probably not a good idea for large files.
With a URL like "filesystem:mydownload.zip" You'd first have to save the file with the filesystem API. You can find some inspiration on html5rocks

Google Analytics don't seem to be firing

I've tried to look around many threads here around GA, I feel like I've done what's required. My site consist of HTML5 and angular.js, the page is structured roughly as follow (through ng-include)
index.html
|-header
--|-navigation
|-content
|-footer
when a link from navigation bar is clicked, the content will change (partials page in angular), header, footer stays the same.
The last script tag in my < head > is as follow (inside index.html)
<script type="text/javascript">
var globalLanguage = 'en';
// GA tracking variable
var _gaq = [['_setAccount', 'UA-XXXXXXXX-X'], ['_trackPageview']];
</script>
and at the bottom part of index.html, before the closing < / body > tag:
<script type="text/javascript">
(function(d, t) {
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
g.async = 1;
g.src = '//www.google-analytics.com/ga.js';
g.type = 'text/javascript';
s.parentNode.insertBefore(g, s);
}(document, 'script'));
</script>
All my angular controller function, call a common function as described in Tracking Google Analytics Page Views with Angular.js
function gaqPageView($scope, $location, $window) {
console.log('triggering google analytics');
$scope.$on('$viewContentLoaded', function(event) {
console.log('event triggered, tracking: ' + $location.path());
$window._gaq.push([ '_trackPageview', $location.path() ]);
});
}
I do see the console log statements, there's no error in the console either.
When I print out the content of _gaq, I do get an array that grows as I navigate around the page (which mean my _gaq.push call is working just fine).
However, in my the network call (in chrome dev tool), I don't see any _utm.gif call to Google Analytics. (Basics of Debugging Google Analytics Code: GA Chrome Debugger and other tools).
What am I missing here? seems like the google analytics is not firing off the event and reporting it?
Edit: I am pretty sure I am silly here, the _gaq variable itself is just a normal javascript array, so of course _gaq.push work just fine. But what am I missing to get Google Analytics to kick in and start sending the content of that _gaq?
Are you currently running your server on localhost, or an intranet name without a "." -- the tracking GIF request doesn't get made for localhost servers by default.
See Google Analytics GIF request not sent.
Another idea: Usually _gaq is defined as an array only if it's not already defined. If ga.js has already executed, you might be overwriting the _gaq object. It doesn't seem likely from your code organization, but...
Try replacing
var _gaq = [['_setAccount', 'UA-XXXXXXXX-X'], ['_trackPageview']];
with
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXXX-X'], ['_trackPageview']);

Resources