I am working on a bookmarking feature for a book reader iOS app I have. The way it is setup now, the user scrolls through a view, and when they want to save, or bookmark their spot before they leave, they hit a save button on the bottom toolbar.
When they hit this save button, the saved action is called:
-(IBAction) savePlace:(id)sender{
int pageYOffset = [[webView stringByEvaluatingJavaScriptFromString:#"window.pageYOffset"] intValue];
NSLog(#"%d Set Y Value", pageYOffset);
[[NSUserDefaults standardUserDefaults] setSavedSpot:pageYOffset];
}
Surprisingly enough, I have got this part working. I can hit the save button, the console will read say 200 for where I'm at on the screen, and then when I leave and come back, 200 is again printed out to the console thanks to this method that is called by NSUSerDefaults when the app loads:
- (void) setCurrentSpot:(NSUInteger)ySpot {
NSLog(#"%d Saved Y Value", ySpot);
[webView stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat: #"window.scrollTo(0, %d);", ySpot]];
}
BUT! Nothing happens...I know for a fact that I am saving and correctly retrieving the correct Y-axis value, but when that JavaScript method is called, it won't fire.
To further complicate things, I went ahead and made a custom IBAction that accesses that same ySpot value, and used the exact same JavaScript method to move the view to position 200, and it works perfectly!
What am I missing? I don't see what is going on. Thanks
edit: misread your question,
Perhaps the method you are calling to call that javascript is being called too fast? and not giving the UIWebview time to initialize and react? if it works when you wait on the webview to come upand then call it, that is the only thing i could see.
Related
First I would like to say that I searched and found plenty of answers and even tried a couple (more than...) but to no avail! The error is probably mine but it is time to turn to SO and ask.
Problem description: I have a variable that I want to change the value through the user input (click on btn). As soon as the user chooses the btn it will navigate to a different page that will use the result of the variable to perform certain actions. My issue is that if I alert on my 1st page I get the value being passed by the btn... But on the second page I only get "undefined"
I think it has to do with variable scope and the fact that (I think it works that way anyway) even a window.var will be deleted/purged in a different window.
Anyway, the code is something like this (on the 1st page/file):
var somAlvo;
$('#omissL').click(function(){
somAlvo = 'l';
window.location.href='index_ProofOfConcept_nivel1.html';
});
And on the "receiving end" I have the following code
<head>
...
<script type="text/javascript" src="testForm_javascript.js"></script>
to "import" the js file with the variable and:
var processo = somAlvo;
alert(processo);
I tried declaring window, not using var inside the function and so on...
This is a proof of Concept for a project in my local University, where I'm working as a research assistant (so, this is not homework ;) )
Thanks for any help/hints...
You are right in that when you navigate to another page, the entire JavaScript runtime is reset and all variables lost.
To preserve a value across page loads you have two options:
Include it as part of a query string when navigating to the new page.
Set a cookie.
You may also want to look into loading the new content through an AJAX call and replacing what is displayed. This way you won't reload the entire page which won't cause the JavaScript runtime to be reset.
I have an ASP.NET MVC app. My app uses jQuery on the client side. The user can enter values into several fields and click "Refresh". The Refresh is behaving oddly.
When Refresh is clicked, I execute the following JavaScript:
function refresh() {
var chosen = "(someField eq 'value')";
try {
if (chosen) {
var url = 'http://localhost:8089/item&c=' + chosen;
alert(url);
window.location = url;
} else {
window.location = 'http://localhost:8089/item';
}
return false;
} catch (ex1) {
alert(ex1);
}
}
The value for chosen is actually generated via a function. I've noticed when I use a certain type of control, the page hangs. Here is what is odd, I can see the request made in Fiddler. Yet, my breakpoint in my controller action is never hit. If I copy and paste the url from the alert call into the address bar, my breakpoint gets successfully hit. So, I'm totally confused.
Due to the fact this involves a specific control, I at first assumed this was a JavaScript error. However, I do not see any JavaScript error in the console. I also checked to see if any exceptions were being swallowed and I did not see any.
The fact I see the request in Fiddler, would imply that I'm getting to the web server. Yet, if I have a breakpoint on the very first line of the controller action, I would expected that to trip. It does not trip in the scenario where I use the control. It does trip if I do NOT use the control. The result in Fiddler sits at '-'. It never returns. Plus, I do not get an exception thrown in my ASP.NET view.
I'm totally stuck on this and looking for ideas of potential causes. Thank you.
This behavior is usually the result of a problem during model binding for the controller.
A quick step to try is making sure the query string values you are sending are properly encoded.
var chosen = "(someField eq 'value')";
chosen = encodeURIComponent(chosen);
Would eliminate any bad character problems that the model binder might be having.
I am successfuly using an invisible UIWebView as an execution engine for Javascript snippets. Contrary to what certain pages suggest, it does not require to be visible. If declared dead simply as
UIWebView* myJSExecutor = [UIWebView new];
not only it executes any stringByEvaluatingJavaScriptFromString: thrown at it, it even bubbles alert() to the desktop! (Not that it's something you would like to do often) Disclaimer: tested only on iOS 5+
Now, I have another normally visible UIWebView with normal webpage content, and I want it to suspend JavaScript execution: that is stop acting on timer and DOM events. I thought that removeFromSuperview with stopLoading and setting delegate = nil would do the trick. But no, as soon as I add the UIWebView back to some visible view, I can see that the timers were running all the time.
I understand the schizophreny of my requirement. I appreciate it working in the background on one hand (contrary to some observations), but I want to suspend it on the other hand. But still I would like to ask if there is any, perhaps even private way to suspend it. Safari for iOS is capable of suspending browser tabs in the background. Chrome for iOS can't, which may be a sad negative proof :(
If you're looking for crazy, I have an idea.
The only way I know to pause JavaScript is to show an alert, confirm, prompt, or sending an ajax request with async=false.
Is the alert hidden when the UIWebView is hidden? If so, you could send an alert when you want it to freeze. The user would have to dismiss it when you showed the view again:
[web stringByEvaluatingJavaScriptFromString:#"alert('Press OK to continue...')"];
Or maybe you could dismiss it programmatically. I'm sure you'd agree that this whole suggestion is bound for trouble, but it's a thought.
Do you need a full UIWebView? If not you could just invoke JavaScriptCore directly.
- (NSString *)runJS:(NSString *)aJSString
{
JSContextRef ctx = JSGlobalContextCreate(NULL);
JSStringRef scriptJS = JSStringCreateWithUTF8CString([aJSString UTF8String]);
JSValueRef exception = NULL;
JSValueRef result = JSEvaluateScript([self JSContext], scriptJS, NULL, NULL, 0, &exception);
JSGlobalContextRelease(ctx);
...
This would give you more control over the entire JS runtime, but unfortunately I've not found an API to suspend execution of timers other than releasing the whole context.
For a more complete example of how to use JavaScriptCore see https://github.com/jfahrenkrug/AddressBookSpy/blob/master/AddressBookSpy/AddressBookSpy/ABSEngine.m
This might sound obvious, but if you can edit the JS you're running in the UIWebView, can't you just store a global variable in the JS called 'paused', and check that when your timers are firing?
var paused = false;
var thread = setInterval(function() {
if(!paused) {
// normal timer checking etc
}
}, 300);
Then just fire [webView stringByEvaluatingJavaScriptFromString:#"paused = true;"] when you remove the webview, and set paused = false when you add it back to the view.
This is a MVC3 project using razor. Instead of displaying another view to inform the user that the changes have been saved successfully I would like to simply fire a JavaScript popup informing them... Everything I have found on the web either opens a whole new browser window, or misses what I am trying to accomplish all together... I know there is a simpler way to go about doing this but this is where I am... At the end of the controller function that does the save on the return I simply use redirect and send it to another controller function that displays a screen saying "Changes Have Been Saved Successfully" then the user clicks a button there which will take them back to the index page... IMO this is a bit shotty and think it can be cleaned up through the use of Javascript...I have not found any luck on this yet.. Currently the below code is what I am using:
Function SomeFunctionName()
db.SaveChanges()
Return RedirectToAction(ChangesSaved)
End Function
Function ChangesSaved()
Return View()
End Function
And the javascript that I have implemented in the ChangesSaved view.
#Code
ViewData("Title") = "ChangesSaved"
End Code
<script type="text/javascript">
alert("Changes Have Been Saved Successfully");
</script>
There are a few problems with this though...
How do I tell the javascript When the user clicks OK it should take them to another page.
I did just try the below and since I am very new to java/javascript it failed:
var r=alert("Changes Have Been Saved Successfully");
if (r == true) {
#html.Action("***********","Admin")
}
If I were you I would post your form using Jquery. Then you can set a callback. In Mvc you can return JSON data, a simple value indicating that the save worked would be enough. Then you can call your alert although you might consider using a jQuery UI dialog as it's way more flexible. If you haven't ever used jQuery I wouldn't be afraid, it's easy and there is a lot of great examples out there.
Take a look at this http://api.jquery.com/jQuery.post/ and this, ASP.NET MVC controller actions that return JSON or partial html
I have the following structure
UIViewController1
--> UIWebView
I run a local HTML File in WebView from Documents-Folder. Within the HTML I have a short JavaScript snippet, which checks the interface Orientation via orientationObserver.
The UIViewController1 is locked to landscape.
OrientationObserver always returns "portrait", should return "landscape". I don't know what causes the wrong return value.
What could cause the orientationObserver to return the wrong orientation in this constellation ?
I'm really stuck here, and I need to get the right orientation returned.
Any help is appreciated.
Finally, after four days of banging my head against the iMac i found a solution for this.
In UIWebView there is no window.orientation available (i wonder why!?). If a JavaScript request the value, it gets "0" what means the orientation is "portrait".
You can go around the problem if you add the "orientation" Setter to the window.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)req navigationType:(UIWebViewNavigationType)navigationType {
[webView stringByEvaluatingJavaScriptFromString:#"window.__defineGetter__('orientation', function(){return 90;});"];
return YES;
}
This implements a getter within window and the JavaScript get's the return value. If you want your app to respond to interface orientation changes, you can set the values in the delegates again to the correct values (-90, 0, 90 or 180).