2

I'm trying to pass a value from swift to angularJS. The following is the swift code that calls the javascript function:

let userScriptSetToTrue = WKUserScript(
    source: "setTrackingToggleToTrue();",
    injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
    forMainFrameOnly: true
)
contentController.addUserScript(userScriptSetToTrue)

...
let js = "setTrackingToggleToTrue();"
self.webView?.evaluateJavaScript(js) {
     (_, error) in print(error)
}

And then the javascript calls the angular controller function:

<script>
    function setTrackingToggleToTrue() {
        angular.element(document.getElementById('trackingToggle')).scope().setTracking(true);
    }
</script>

But I got the following error in the javascript side:

TypeError: undefined is not an object (evaluating 'angular.element(document.getElementById('trackingToggle')).scope().setTracking')

It seems the document.getElementById('trackingToggle') is not available but I can see the following in the safari web inspector elements tab

<div class="list-group-item">
    <tracking-toggle-button
            id="trackingToggle"
            state="trackingEnabled"
            class="pull-right"
            on-toggle="updateTrackingPreference(newState);">
    </tracking-toggle-button>
    <label class="tracking-label">My Location</label>
</div>

What would be the reason for this error? or is there a better way to pass a value from swift all the way to angular controller?

Update The angular app is using UI routing and loads page content from different templates based on routing. I later find out the function setTrackingToggleToTrue() is called before its template is loaded and thus no trackingToggle is available at function call. Is there another way to call an angular function outside the controller without referencing any document element?

Thanks.

2
  • 1
    try angular.element(document).find('trackingToggle') Instead of document.getElementById('trackingToggle') Commented Jul 29, 2016 at 18:43
  • I still run into the same error: `undefined is not an object (evaluating 'angular.element(document).find('trackingToggle').scope().setTracking') Commented Jul 29, 2016 at 18:50

2 Answers 2

1

It turns out WKWebView.evaluateJavaScript() can only call javascript on the top scope. The called top scope javascript can't use angular.element() to call an angular controller function based on an element loaded from a template based on routing.

I end up using an awkward way to work around it. The top scope java script set the toggle button value in local storage and the angular controller function will check the value till it's available. I also have to use $scope.$apply() manually to reflect the change in UI.

The same might be achieved via promise. I'll try the promise way later.

Sign up to request clarification or add additional context in comments.

Comments

0

Please find working fiddle here: http://jsfiddle.net/varit05/06Ldnys8/25/

Controller:

var app = angular.module('app', []).controller('ctrl', function($scope) {
  $scope.inside = { 'name': 'guy', 'idk': 'blah' };
  $scope.abc = function(value) {
    console.log(value);
  }
});

var getStuff= function() {
  var outside = angular.element(document.getElementById('stuff')).scope().abc('called');
 //console.log(outside.inside)
}

HTML:

<div ng-app="app" ng-controller="ctrl" id="stuff">
</div>

<button onclick="getStuff()">get stuff</button>

Hope it helps you!

Cheers!

5 Comments

Thanks for the fiddle. I also feel it should work but somehow I keep getting the same error. Maybe it's not caused by the trackingToggle not available but something else.
Can you try calling true inside single quote. I too got the undefined error.
I add single quotes to true but nothing changed.
Can you please post the error or can you please create a plunker for your problem?
I added an update to the question. The reason was the function was called before trackingToggle element is loaded.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.