I am new to the whole front-end client scripting scene and have encountered a few difficulties when working on my most recent project. I have looked around the website and could not find anything that answered my question. There may be something here and I have just not found it because of my inexperience and if there is it would be nice if you can provide a link to those resources.
I am currently working on building a client that makes ajax calls to a cross-domain asp.net web api that I have built. I know that the web api works as it has been tested in fiddler. I have also managed to successfully make calls on a click event.
The problem is that I cannot seem to get this working on page load and with knockoutjs. I have tried to do a simple list that is populated with data when the page loads but when I load the page and check fiddler I can see that the ajax calls are not being made. This possibly explains why when I load the page the content isn't there. I have tried inserting some static data to view model and the binding worked so it seems it may be the case that there is something blocking the ajax calls.
I have looked at examples and have knocked up some code. I cannot see any problems with the code but as I am inexperienced there is certainly a possibility that I am missing something. There may also be more efficient ways to do model binding, if so, I would appreciate any advice from someone more experienced.
The code is:
#{
ViewBag.Title = "KnockoutTesting";
}
<!-- MAIN -->
<div id="main">
<!-- wrapper-main -->
<div class="wrapper">
<ul data-bind="foreach: places">
<li>
<span data-bind="text: title"></span>
</li>
</ul>
</div>
</div>
#section scripts {
<script type="text/javascript" src="../../Scripts/jquery-1.7.2.js"></script>
<script type="text/javascript" src="../../Scripts/knockout-2.1.0.js"></script>
<script type="text/javascript">
function PlacesViewModel() {
var self = this;
function Place(root, id, title, description, url, pub) {
var self = this;
self.id = id;
self.title = ko.observable(title);
self.description = ko.observable(description);
self.url = ko.observable(url);
self.pub = ko.observable(pub);
self.remove = function () {
root.sendDelete(self);
};
self.update = function (title, description, url, pub) {
self.title(title);
self.description(description);
self.url(url);
self.pub(pub);
};
};
self.places = ko.observableArray();
self.add = function (id, title, description, url, pub) {
self.places.push(new Place(self, id, title, description, url, pub));
};
self.remove = function (id) {
self.places.remove(function (place) { return place.id === id; });
};
self.update = function (id, title, description, url, pub) {
var oldItem = ko.utils.arrayFirst(self.places(), function (i) { return i.id === id; });
if (oldItem) {
oldItem.update(title, description, url, pub);
}
};
self.sendDelete = function (place) {
$.ajax({
url: "http://localhost:1357/api/places" + place.id,
type: "DELETE"
});
}
};
$(function () {
var viewModel = new PlacesViewModel();
ko.applyBindings(viewModel);
$JQuery.support.cors = true;
$.get("http://localhost:1357/api/places", function (places) {
$.each(places, function (idx, place) {
viewModel.add(place.PlaceID, place.Title, place.Description, place.URL, place.Public);
});
}, "json");
});
</script>
}
It has been simplified for the sake of getting it to work before I add more functionality.
Thanks for your time.
I believe your problem may lie in your Web API implementation. Both the client and the server must support CORS. According to Carlos' post, Web API does not natively support CORS. His post includes a code sample.
Related
Is there a way to write a google apps script so when ran, a second browser window opens to www.google.com (or another site of my choice)?
I am trying to come up with a work-around to my previous question here:
Can I add a hyperlink inside a message box of a Google Apps spreadsheet
This function opens a URL without requiring additional user interaction.
/**
* Open a URL in a new tab.
*/
function openUrl( url ){
var html = HtmlService.createHtmlOutput('<html><script>'
+'window.close = function(){window.setTimeout(function(){google.script.host.close()},9)};'
+'var a = document.createElement("a"); a.href="'+url+'"; a.target="_blank";'
+'if(document.createEvent){'
+' var event=document.createEvent("MouseEvents");'
+' if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1){window.document.body.append(a)}'
+' event.initEvent("click",true,true); a.dispatchEvent(event);'
+'}else{ a.click() }'
+'close();'
+'</script>'
// Offer URL as clickable link in case above code fails.
+'<body style="word-break:break-word;font-family:sans-serif;">Failed to open automatically. Click here to proceed.</body>'
+'<script>google.script.host.setHeight(40);google.script.host.setWidth(410)</script>'
+'</html>')
.setWidth( 90 ).setHeight( 1 );
SpreadsheetApp.getUi().showModalDialog( html, "Opening ..." );
}
This method works by creating a temporary dialog box, so it will not work in contexts where the UI service is not accessible, such as the script editor or a custom G Sheets formula.
You can build a small UI that does the job like this :
function test(){
showURL("http://www.google.com")
}
//
function showURL(href){
var app = UiApp.createApplication().setHeight(50).setWidth(200);
app.setTitle("Show URL");
var link = app.createAnchor('open ', href).setId("link");
app.add(link);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
If you want to 'show' the URL, just change this line like this :
var link = app.createAnchor(href, href).setId("link");
EDIT : link to a demo spreadsheet in read only because too many people keep writing unwanted things on it (just make a copy to use instead).
EDIT : UiApp was deprecated by Google on 11th Dec 2014, this method could break at any time and needs updating to use HTML service instead!
EDIT :
below is an implementation using html service.
function testNew(){
showAnchor('Stackoverflow','http://stackoverflow.com/questions/tagged/google-apps-script');
}
function showAnchor(name,url) {
var html = '<html><body>'+name+'</body></html>';
var ui = HtmlService.createHtmlOutput(html)
SpreadsheetApp.getUi().showModelessDialog(ui,"demo");
}
There really isn't a need to create a custom click event as suggested in the bountied answer or to show the url as suggested in the accepted answer.
window.open(url)1 does open web pages automatically without user interaction, provided pop- up blockers are disabled(as is the case with Stephen's answer)
openUrl.html
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<script>
const url1 ='https://stackoverflow.com/a/54675103';
const winRef = window.open(url1);
winRef ? google.script.host.close() : window.alert('Allow popup to redirect you to '+url1) ;
window.onload=function(){document.getElementById('url').href = url1;}
</script>
</head>
<body>
Kindly allow pop ups</br>
Or <a id='url'>Click here </a>to continue!!!
</body>
</html>
code.gs:
function modalUrl(){
SpreadsheetApp.getUi()
.showModalDialog(
HtmlService.createHtmlOutputFromFile('openUrl').setHeight(50),
'Opening StackOverflow'
)
}
Google Apps Script will not open automatically web pages, but it could be used to display a message with links, buttons that the user could click on them to open the desired web pages or even to use the Window object and methods like addEventListener() to open URLs.
It's worth to note that UiApp is now deprecated. From Class UiApp - Google Apps Script - Google Developers
Deprecated. The UI service was deprecated on December 11, 2014. To
create user interfaces, use the HTML service instead.
The example in the HTML Service linked page is pretty simple,
Code.gs
// Use this code for Google Docs, Forms, or new Sheets.
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu('Dialog')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Dialog title');
}
A customized version of index.html to show two hyperlinks
<a href='http://stackoverflow.com' target='_blank'>Stack Overflow</a>
<br/>
<a href='http://meta.stackoverflow.com/' target='_blank'>Meta Stack Overflow</a>
Building of off an earlier example, I think there is a cleaner way of doing this. Create an index.html file in your project and using Stephen's code from above, just convert it into an HTML doc.
<!DOCTYPE html>
<html>
<base target="_top">
<script>
function onSuccess(url) {
var a = document.createElement("a");
a.href = url;
a.target = "_blank";
window.close = function () {
window.setTimeout(function() {
google.script.host.close();
}, 9);
};
if (document.createEvent) {
var event = document.createEvent("MouseEvents");
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
window.document.body.append(a);
}
event.initEvent("click", true, true);
a.dispatchEvent(event);
} else {
a.click();
}
close();
}
function onFailure(url) {
var div = document.getElementById('failureContent');
var link = 'Process';
div.innerHtml = "Failure to open automatically: " + link;
}
google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).getUrl();
</script>
<body>
<div id="failureContent"></div>
</body>
<script>
google.script.host.setHeight(40);
google.script.host.setWidth(410);
</script>
</html>
Then, in your Code.gs script, you can have something like the following,
function getUrl() {
return 'http://whatever.com';
}
function openUrl() {
var html = HtmlService.createHtmlOutputFromFile("index");
html.setWidth(90).setHeight(1);
var ui = SpreadsheetApp.getUi().showModalDialog(html, "Opening ..." );
}
I liked #Stephen M. Harris's answer, and it worked for me until recently. I'm not sure why it stopped working.
What works for me now on 2021-09-01:
function openUrl( url ){
Logger.log('openUrl. url: ' + url);
const html = `<html>
<a id='url' href="${url}">Click here</a>
<script>
var winRef = window.open("${url}");
winRef ? google.script.host.close() : window.alert('Configure browser to allow popup to redirect you to ${url}') ;
</script>
</html>`;
Logger.log('openUrl. html: ' + html);
var htmlOutput = HtmlService.createHtmlOutput(html).setWidth( 250 ).setHeight( 300 );
Logger.log('openUrl. htmlOutput: ' + htmlOutput);
SpreadsheetApp.getUi().showModalDialog( htmlOutput, `openUrl function in generic.gs is now opening a URL...` ); // https://developers.google.com/apps-script/reference/base/ui#showModalDialog(Object,String) Requires authorization with this scope: https://www.googleapis.com/auth/script.container.ui See https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes
}
https://developers.google.com/apps-script/reference/base/ui#showModalDialog(Object,String) Requires authorization with this scope: https://www.googleapis.com/auth/script.container.ui See https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes
I'm using ng-selectize directive to a select box using angularJS. Options to the slectbox are retrieved from an AJAX call. AJAX call response is coming in proper format.If do inspect element, select box options are populated properly. But in the UI, options are not rendered. Is there any specific reason for this behaviour? The same code is working fine in another place.
Here is my code:
HTML:
<select multiple="multiple"
ng-model="email.existing"
ng-options="obj.email for obj in emailLists track by obj.email"
placeholder="Choose from existing email address"
selectize>
Javascript
angular.module('myApp', [
'myApp.controllers',
'myApp.services',
'ngDialog',
'angular-selectize'
]);
angular.module('myApp.services', []).
factory('myAPIservice', function($http) {
var myAPI = {};
myAPI.getAllEmail = function( data ) {
return $http.post(APP_BASE_URL + "director/getallemail", data );
}
return myAPI;
});
angular.module('myApp.controllers', [])
.controller('myCntrl', function($scope, myAPIservice, ngDialog) {
myAPIservice.getAllDirectorsEmail({}).success(function (response) {
$scope.emailLists = response;
});
});
The above code retrieves email list from url. Sample response will look like this.
AJAX Response
If I change the javascript code to
angular.module('myApp.controllers', [])
.controller('myCntrl', function($scope, myAPIservice, ngDialog) {
$scope.emailLists = new Array({email:'abc#def.com'},{email:'lmn#opqr.com'})
});
and the response will be
Without AJAX call
Can anyone help me resolve this issue?
I know it has been given some answers but I will go for it :). As the title says i want to add popover bootstrap but with ajax loaded content. my html, but i want a Loading message to appear first and then the content.
<p class='entry' data-adjaxload = '/calendar/entry/1'>Title1</p>
<p class='entry' data-adjaxload = '/calendar/entry/2'>Title2</p>
<p class='entry' data-adjaxload = '/calendar/entry/3'>Title3</p>
my django view is the following
def entry_details(request, entry_id):
entry = get_object_or_404(Entry, pk=entry_id)
args = dict(entry=entry, user=request.user)
if request.is_ajax():
return render_to_response('mycal/ajax/entry_details.html', args)
else:
entry_form = EntryForm(instance=entry)
args.update(entry_form=entry_form)
return render_to_response('mycal/entry_details.html', args)
Pretty simple. I am using the same view to either load html content via ajax in the popover, or a details page via normal get request
the ajax details page:
<div class="entry">
<p>{{entry.title}}</p>
<p>{{entry.date}}</p>
<p>{{entry.customer}}</p>
</div>
and the script
$(document).ready(function(){
$('p.entry').each(function (){
var i = $(this);
$(i).bind('mouseenter', function(){
i.popover({
html:True,
title:i.html(),
content:'Loading'
}).popover('show');
$.ajax({
url:i.data('ajaxload'),
dataType:'html',
success:function (data){
i.popover({content:data}).popover('show');
}
});
});
$(i).bind('mouseleave', function(){
i.popover('hide');
});
});
});
But whilst it does run tha ajx and fetches the html, it won't load them onto the popover. How can I change that?
Just fiddled what you are looking for with popover content being updated dynamically using echo/json.
Just roll over the p element and wait for the 3 second delay.
If as you say, the data is being loaded properly then the only change needed is:
var popover = i.data('popover');
popover.options.content = data.text;
i.popover('show');
I have some code, some to change the class of a div, the rest to load content into the ajax div.
The ajax div however, does not load content. Why might this be?
<script>
window.onload = function () {
var everyone = document.getElementById('everyone'),
favorites = document.getElementById('favorites');
everyone.onclick = function() {
loadXMLDoc('indexEveryone');
var otherClasses = favorites.className;
if (otherClasses.contains("Active")) {
everyone.className = 'statusOptionActive';
favorites.className = 'statusOption';
}
}
favorites.onclick = function() {
loadXMLDoc('indexFav');
var otherClasses = everyone.className;
if (otherClasses.contains("Active")) {
favorites.className = 'statusOptionActive';
everyone.className = 'statusOption';
}
}
function loadXMLDoc(event) {
$.ajax({
url: "../home/" + event.data + ".php",
type: "GET",
success: function (result) {
$("#centreCont").html(result);
}
});
}
}
</script>
These divs start the ajax code (or should do at least)
<div id="everyone" class="statusOptionActive" onclick="loadXMLDoc('indexEveryone')">Everyone, everywhere</div>
<div id="favorites" class="statusOption" onclick="loadXMLDoc('indexFav')">Favourites Only</div>
Why won't it work :(
DEMO
Delete your div onclick event,since already you are manipulating your click event in the script.
Edited div
<div id="everyone" class="statusOptionActive">Everyone, everywhere</div>
<div id="favorites" class="statusOption">Favourites Only</div>
And I don know what argument you are passing in to loadXMLDoc('indexFav'); and loadXMLDoc('indexEveryone'); apart from that your javascript code is correct.
Hope this helps
Thank you
One obvious problem I can see is that you pass a string to loadXMLDoc, then you try to access .data on that string.
I have an MVC view where I am doing some paging of data, using the PagedList component. My JavaScript to support this looks as follows:
$(function () {
var getPage = function () {
var $a = $(this);
var options = {
url: $a.attr("href"),
type: "get"
};
$.ajax(options).done(function (data) {
var target = $a.parents("div.pagedList").attr("data-ExchangeSite-target");
data: $("form").serialize(),
$(target).replaceWith(data);
});
return false;
};
$(".main-content").on("click", ".pagedList a", getPage);
});
My .cshtml file looks, in part, like this:
#model ExchangeSite.Entities.BicycleSearchSeller
<div id="itemList">
<div class="pagedList" data-ExchangeSite-target="#itemList">
#Html.PagedListPager(Model.BicycleSellerListingList, pageNumber => Url.Action("Index", new {pageNumber}),
PagedListRenderOptions.ClassicPlusFirstAndLast)
</div>
...
...
In IE9, this works perfectly. When I click on a specific page number, or the next/previous page, an asynch call is made to my controller to refresh the list of data ("itemList"). However, in Chrome, two calls are made to my controller. One is an Ajax call, the other is not. Can anyone tell me why, in Chrome, two calls are made to my controller? If you need to see more code, please let me know.
There seems to be some buggy line in your success callback:
data: $("form").serialize(),
It is terminated with a comma instead of semicolon. It also contains a colon after data. IE might be a little more tolerant towards broken javascript compared with Google Chrome.