Open all links using system browser inside an ionic app - angularjs

I need that all links inside a certain section of my app open in the system browser. The trick is that those links come from an external source (an API) so I can't add the ng-click function that helps me to open the links externally.
I'm using in-app-browser plugin (ng-cordova). In fact I have other links that open externally but in this case the links can be in any part of the content so my question would be how could I add the ng-click directive to all links after they are loaded? or if it's possible, how to config in-app-browser plugin to open ALL links in system browser?
By the way, the simple links don't open even in the inappbrowser: I tap on them and nothing happens.
Thanks for the help

AFAIK there isn't a way of doing that automatically, you must use the in app browser js code to open links externally consistently in every platform.
Your question doesn't give a clear example of what the server returns so I'm assuming you are getting a full block of html and are just rendering it on the screen. Assuming a request return something basic like :
<div id="my-links">
<a href='http://externallink.com'> External Link 1 </a>
<a href='http://externallink.com'> External Link 2 </a>
<a href='http://externallink.com'> External Link 3 </a>
</div>
And your request looks like:
$http.get('givemelinks').success(function(htmlData){
$scope.myContent = htmlData;
})
If you have access to the server side and can make changes:
Add a "inappbrowser" parameter to your request to detect if it should return inappbrowser compatible links and change the response from your server to be something like:
if (inappbrowser) {
<div id="my-links">
<div ng-click='openExternal($event)' data-external='http://externallink.com'> External Link 1 </div>
<div ng-click='openExternal($event)' data-external='http://externallink.com'> External Link 2 </div>
<div ng-click='openExternal($event)' data-external='http://externallink.com'> External Link 3 </div>
</div>
} else {
<div id="my-links">
<a href='http://externallink.com'> External Link 1 </a>
<a href='http://externallink.com'> External Link 2 </a>
<a href='http://externallink.com'> External Link 3 </a>
</div>
}
And have a generic openExternal method:
$scope.openExternal = function($event){
if ($event.currentTarget && $event.currentTarget.attributes['data-external'])
window.open($event.currentTarget.attributes['data-external'], '_blank', 'location=yes');
}
If you can't change the server side
Parse the response and replace the links with ng-clicks:
$http.get('givemelinks').success(function(htmlData){
htmlData = htmlData.replace(/href='(.*)'/,'ng-click="openExternal($event)" data-external="$1"').replace(/<a/,"<div").replace(/a>/,"div>")
$scope.myContent = htmlData;
})
And use the same openExternal method as above.
I'm replacing the anchors with divs to prevent changing the app routes. That might not be necessary in every app.
To make this even better you should bundle it in a open-external directive so you can use it in multiple controllers and keep them cleaner.

Because the HTML is already rendered when it comes to Angular, and the inAppBrowser plugin only works if called by explicit Javascript, there is nothing you can do that doesn't involve manually changing the HTML or using plain javascript.
Changing the HTML is just a Bad Idea®, especially if you try to do it by using regex matching.
That leaves javascript:
Restangular.all('stories').getList().then(function(stories){
$scope.stories = stories;
updateLinks();
});
function updateLinks(){
//use $timeout wait for items to be rendered before looking for links
$timeout(function(){
var $links = document.querySelectorAll(".stories .story a");
for(var i =0; i < $links.length; i++) {
var $link = $links[i];
var href = $link.href;
console.log("Hijacking link to ", href);
$link.onclick = function(e){
e.preventDefault();
var url = e.currentTarget.getAttribute("href");
window.cordova.inAppBrowser.open(url, "_system");
}
}
});
}

Install next plugin:
cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser.git
Now, you can use _system, _blank or _self for destination:
window.open(url, '_blank');
More info: https://www.thepolyglotdeveloper.com/2014/07/launch-external-urls-ionicframework/

You can override the default link tag functionality as seen here:
https://www.thepolyglotdeveloper.com/2014/12/open-dynamic-links-using-cordova-inappbrowser/
Best,

<ul>
<li> <a href="#" ng-click='openlink($event)' data-link='https://www.link1.com'> Link 1 </a></li>
<li> <a href="#" ng-click='openlink($event)' data-link='https://www.link2.com'> Link2 </a></li>
<li> <a href="#" ng-click='openlink($event)' data-link='https://www.link3.com'> Link 3 </a></li>
</ul>
In controller -
angular.module('app', [])
.controller('LinkCtrl', function($scope) {
$scope.openlink = function($event)
{
if ($event.currentTarget && $event.currentTarget.attributes['data-link'])
{
window.open($event.currentTarget.attributes['data-link'], '_system', 'location=yes');
}
}
})

Related

How to allow external link in angularjs when using ng-bind-html

Here is the rendered code
<div>dfdbfbdfbdfbdfbdfbfb gdfgfggtbrtb
<a href="www.github.com" target="_blank"> rtrtrt
</a>
<p></p>
</div>
I get this, when i click in the hyperlinked text
https://myapp.io/www.github.com
Remember to use HTTP protocol with external links, if you don't use HTTP before the link, it will be considered as local resource link. In your above mentioned code you should use
Github
Instead of
Github
Try <a href="https://www.github.com" target="_blank"> the link destination you pasted is relative to the domain you are in.
The easy way is to use $window in the controller and a ng-click in the view.
In the view:
<a ng-click="myFunctionToGoAwayFromAngularJS()">click me</a>
And in the controller:
$scope.myFunctionToGoAwayFromAngularJS = function () { $window.open("https://www.github.com"); };
Obviously you need to inject $window in your controller. This way you can assign ng-click in whatever tag you want, not only to anchor tags.

When I click a button it should display the html page in angularjs(single page application)

I am going to design a website That should display the content of html when I click a button.
HTML
<a ui-sref="about">about</a>
<a href="" ng-click="home()" >home</a><div ng-include="templateURL"></div>
<ui-view></ui-view>
JS:
app.controller("home", hom); function hom($scope) {
$scope.home = function(){
$scope.templateURL = 'templates/hello.html'; }}
Answer to your problem is ngRoute / ui-route.
You can one of the above-mentioned solutions.
check demo here:
https://www.w3schools.com/angular/angular_routing.asp

angular1 with electron: ng-dblclick not working

I am using electron with angular 1.6.4.
I have a controller, in which I dynamically generate li. I want to bind a double click event on this list items, but I could not succeed.
function TheController($http, $scope, KeyService) {
$scope.openItem = function(id) {
console.log(id);
}
var key = KeyService.getLastKey();
connectToBackend($http,key);
}
function connectToBackend($http, key) {
$http.get(ENDPOINT).then(
function(result) {
//do some work
document.getElementById("list").innerHTML += `<li draggable="true" ondragstart="itemDrag(event)" id=${theID} ng-dblclick="openItem(this.id)"><i class="fa fa-folder-open"></i> ${result}</li><hr>`;
},
function(e) {
//error
}
);
}
If I double-click here, absolutely nothing happens - not even an exception.
If I use ondblclick, it works if I define openItem in renderer.js. But I'd rather like to have it defined inside TheController, to keep some order and to be able to access injected services.
Is this possible? Is the drag stuff maybe interfering?
The directly appended html wouldn't work until you compile it. You should manually compile it before injecting it into DOM tree.
document.getElementById("list")
.appendChild($compile(`
<li draggable="true" ondragstart="itemDrag(event)"
id=${theID} ng-dblclick="openItem(this.id)">
<i class="fa fa-folder-open"></i> ${result}
</li>
<hr>`)($scope);
Generally doing DOM manipulation from directly controller is anti-pattern as it makes your controller code to more tightly coupled with view/html.
Rather I'd suggest you to use ng-inlcude directive and place custom template in ng-template script. So that it will available any time inside $templateCache of angular.
<script id="myCustom.html" type="text/ng-template">
<li draggable="true" ondragstart="itemDrag(event)"
id="{{theId}}" ng-dblclick="openItem(id)">
<i class="fa fa-folder-open"></i>
<div ng-include="ENDPOINT"></div>
</li>
</script>
and then your html will look like below.
Html
<div id="list">
... Your content ..
</div>
<div ng-include="'myCustom.html'"></div>
If you noted, I directly used ENDPOINT directly inside ng-include for the same to work, you have to do some additional setting
angular.module('myApp').config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
// Allow loading from outer templates domain.
'http://somedomain.com/templates/**' //ENDPOINT domain should white listed here
]);
});
Also ondragstart wouldn't call your controllers method, until you patch it up with angular wrapper directive. There are third-party library available out there, you could use any one of them.

Angularjs, Redirect views from controller

I'm new to angularJS. I'm using angularjs to implement a website. The website has two pages. The first page list all items and if user click on it, it will redirect to detail information page.
I have my routes configure as below:
var app = angular.module('myApp', ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("/list", {
templateUrl : "list.html",
controller : "listCtrl"
})
.when("/detail/:id"){
templateUrl : "detail.html"
}
});
In the list.html. I use ng-repeat to display a list of items and a listener on to listen mouse click.
<ul class="list-group">
<li class="list-group-item" ng-repeat="i in items">{{i.name}}
<a href="#" ng-click="goToEdit($index)">
<span class="glyphicon glyphicon-pencil"></span>
</a>
</li>
</ul>
I want to redirect view to detail information in the ng-click function.
I tried $location.path() but it not working.
$scope.goToEdit = function(index){
console.log($location.path());
$location.path("/detail/" + index);
console.log($location.path());
}
This way won't work.
Even though the second log on console show location.path() has been changed to " /detail/id".
If I add $scope.$apply() after $location.path(); Then I will get a action already in progress error.
Do you have any solution???
Thanks
It might have something to do with use href="#" which is not good when using hash based routing
You could just set the href yourself and don't really need the controller function or ng-click
<a ng-href="#/detail/{{$index}}" >
Note that you should really give each item a unique identifier as $index could change due to using filters in ng-repeat or removing data from array
Also you don't have a controller identified for your second route

How to make a button in ng-repeat open a full url link in ionic and angularfire?

Assuming i am using this in my controller
var messagesRef = firebase.database().ref().child("messages");
$scope.messages = $firebaseArray(messagesRef);
And in my html is
<li ng-repeat="message in messages">
<p>{{ message.user }}</p>
<p>{{ message.text }}</p>
<button href="{{ message.weblink }}">OPEN THIS LINK</button>
That {{website.weblink}} for example is www.google.com from my firebase database.
How can i make that button work to open www.google.com using that button because it is not working .
To summarize, <a ng-href=""> should be used instead of <button href="">.
Using Angular markup like {{hash}} in an href attribute will make the
link go to the wrong URL if the user clicks it before Angular has a
chance to replace the {{hash}} markup with its value. Until Angular
replaces the markup the link will be broken and will most likely
return a 404 error. The ngHref directive solves this problem. - ngHref

Resources