Search This Blog

Showing posts with label Ionic. Show all posts
Showing posts with label Ionic. Show all posts

Sunday, 20 March 2016

Markers with different colors in ionic using angularJS, Centering the map

for getting maps in maps in ionic project follow steps in this post

now lets see
1. how to center the map to your screen
2. place markers of different colors
3. increase bounds of your map
4. Show window/message on click of marker

1. Centering the map to current location:
$cordovaGeolocation.getCurrentPosition(options).then(function(position){

var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var mapOptions = {
 center: latLng,
 zoom: 15,
 mapTypeId: google.maps.MapTypeId.ROADMAP

};
                $scope.map = new google.maps.Map(document.getElementById("map"), mapOptions);
});

here getCurrentPositions return the lattitude (lat) and longitude (lon) of my current place.
i will use it in my map options to center it. highlighted above line will set my current location to center my map.

2&3. Place Markers:
lets say i want to place markers in my below lat, lons

var latlons = [{lat:"12.9450362",lon:"77.6970354",title:"msg1"},{lat:"12.9550364",lon:"77.6890356",title:"msg2"},{lat:"12.9950366",lon:"77.6800358",title:"msg3"}];

create a pin to show the marker:

var RedPinColor = "FE7569";
var RedPinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + RedPinColor,
new google.maps.Size(21, 34),
new google.maps.Point(0,0),
new google.maps.Point(10, 34));

var bounds = new google.maps.LatLngBounds(); //for increase/decrease zoom

for (var i = 0; i < markers.length; i++) {
var data = markers[i];
var myLatlng = new google.maps.LatLng(data.lat, data.long);
var marker = new google.maps.Marker({
position: myLatlng,
map: $scope.map,
title: data.title,
icon:RedPinImage,
shadow:pinShadow
});
bounds.extend(myLatlng);
                              $scope.fitBounds(bounds);
}

i am adding bounds which will help me in increase/decrese zoom of my map according to the markers i am adding.

the pin Image can be changed as you need, below are 2 ex:
var GreenPinColor = "69fe75";//"FE7569";
var YellowPinColor = "FFFF00";
var RedPinColor = "FE7569";
var RedPinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + RedPinColor,
new google.maps.Size(21, 34),
new google.maps.Point(0,0),
new google.maps.Point(10, 34));
var YellowPinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + YellowPinColor,
new google.maps.Size(21, 34),
new google.maps.Point(0,0),
new google.maps.Point(10, 34));
var GreenPinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + GreenPinColor,
new google.maps.Size(21, 34),
new google.maps.Point(0,0),
new google.maps.Point(10, 34));
var pinShadow = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_shadow",
new google.maps.Size(40, 37),
new google.maps.Point(0, 0),
new google.maps.Point(12, 35));

Display window/message on click of markers:
google maps offers a InfoWindow to display message on click of markers created above.

the below line create a infowindow.
var infoWindow = new google.maps.InfoWindow();

now need to bind to click event of marker. let see how to do it in a loop (as most of us need to do in looping always)
var infoWindow = new google.maps.InfoWindow();
var bounds = new google.maps.LatLngBounds();


for (var i = 0; i < markers.length; i++) {
var data = markers[i];
var myLatlng = new google.maps.LatLng(data.lat, data.long);
var marker = new google.maps.Marker({
position: myLatlng,
map: $scope.map,
title: data.title,
icon:RedPinImage,
shadow:pinShadow
});
bounds.extend(myLatlng);

//Attach click event to the marker.
(function (marker, data) {
var infoWindowContent = "<div style = 'width:200px;min-height:40px'>"+"<p>" + data.DisplayName + "</p>"
+ "<button ng-click="+"\""+"MarkerClick('"+data.SensorName+"')"+"\""+">"+"Schedule Pick"+"</button>"+"</div>";
console.log(infoWindowContent);
var compiled = $compile(infoWindowContent)($scope);
// console.log(compiled["body"]);
google.maps.event.addListener(marker, "click", function (e) {
//Wrap the content inside an HTML DIV in order to set height and width of InfoWindow.
infoWindow.setContent(compiled[0]);
infoWindow.open($scope.map, marker);
});
})(marker, data);
$scope.map.fitBounds(bounds);
}
});

after a marker is created, using a function and creating a content to be displayed on its click: infoWindwContent

as angular restricts direct html binding need to compile it before attaching it to my window using $compile service. sometimes if the html is unsafe you may need to use $sce service to bind unsafe html.

use setContent to set create content info window
open actually assigns the map and marker to which this infowindow to be attached


using Google Maps in Ionic/Web project

its a simple two step process

1. to use google maps in your project, you should get a api key from google console
2. install cordova GeoLocationAPI
2. add a div and from javascript bind map to it.

1.Creating API key:
1. go to https://console.cloud.google.com/
2. from the top nav bar  project->create project
3. go to use google api
4. select google maps api for javascript
5. enable it and to get the api key you need credentials to be created
6. click on credentials in the left pane
7. click on create credentials (blue button)
8. click on API Key
9. select android as i was trying for an android app
10. give a name to the key and click create.
11. copy the API key it is required for the next step

2. install GeoLocation plugin
          ionic plugin add cordova-plugin-geolocation
reference: https://www.npmjs.com/package/cordova-plugin-geolocation

3. Adding to your project:
 in your ion-view (can be any html need not be ionic) add a div with an id which wanted to use to load map.
<ion-view view-title="Find Near by Bins" ng-controller="FindNearByViewCtrl">
<ion-nav-buttons side="right">
      <i class="ion-log-out" style="font-size:2.2em" ng-click="doLogout()"></i>
 </ion-nav-buttons>
 <ion-nav-buttons side="left">
      <i class="ion-loop" style="font-size:2.2em" ng-click="doRefresh()"></i>
 </ion-nav-buttons>
<ion-content>
<div id="map" data-tap-disabled="true"></div>
</ion-content>
</ion-view>

in your controllers, add the below piece to bind map to #map.
$cordovaGeolocation.getCurrentPosition(options).then(function(position){
 
var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var latLng1 = new google.maps.LatLng(19.1759668, 72.79504659999998);
console.log(""+position.coords.latitude+"---"+ position.coords.longitude);
var mapOptions = {
 center: latLng1,
 zoom: 15,
 mapTypeId: google.maps.MapTypeId.ROADMAP
};
               $scope.map = new google.maps.Map(document.getElementById("map"), mapOptions);
});

thats it displays google map in your project

toggle buttons with ionic

ionic is for mobile apps and toggle button is a common control which is widely used for yes/no, select/unselect purposes. lets see how to use it.

ionic has a tag called, ion-toggle which is used for showing and handling toggle button events. use this in your html:

<ion-toggle ng-model="checked" 
ng-change="TogglePanel(checked)" class="TransparentBG">
<span ng-class="DynHubStatus" class="CategoryTitle">Air</span>
</ion-toggle>

ng-model: checked is to set true or false
ng-change triggers change event and TogglePanel function will be called on change
by default it comes with white background, use css to change that.
in code behind:
$scope.TogglePanel = function(toStatus){
   //use the event to perform your required events.
}

ng-model checked will be set to true on turning on and to false on turning off the button

Saturday, 19 March 2016

Charts with AngularJS/Ionic

angular has plugins which support several kinds of charts. one among them is http://www.chartjs.org/

lets see how to use it:
1. download the package from the above link
2. include css and js
      <link href="css/angular-chart.min.css" rel="stylesheet">
     <script src="js/Chart.min.js"></script>
3. use it in html
    <canvas id="line" class="chart chart-line" data="data" labels="labels" legend="true" options="{showTooltips: false}"></canvas>

initialize values in your controller:
.controller('LineChartCtrl',function($scope){
 
    $scope.labels = ["Jan", "","","Feb","","", "Mar", "","Apr", "May", "Jun", "Jul","Aug","Sep","Oct","Nov","Dec"];
    // $scope.series = ['Series A', 'Series B'];
    $scope.data = [
        [13, 15,12,18,22,24,21,25]
    ];

})

the library also supports gant,bar etc charts follow the above steps to use it.

Sliders with AngularJS/Ionic

angular has growing no.of plugins. it has good  plugin called rzslider. to work with sliders
here is the link to it: https://github.com/angular-slider/angularjs-slider

lets see how to use it:
i want a slider to select a time range of start time to end time, so my slide will look like this:
here is the html:
1. download the package from above link or you can use npm to install to your project folder
2. add the css and js files in header
         <link href="css/rzslider.css" rel="stylesheet">
        <script src="js/rzslider.js"></script>
3. include slide tag in your page
        <rzslider rz-slider-model="minRangeSlider.minValue" rz-slider-                       high="minRangeSlider.maxValue" rz-slider-options="minRangeSlider.options"></rzslider>

mignRangeSlider is initialized in angular code behind.
code:
$scope.minRangeSlider = {
        minValue: 8,
        maxValue: 18,
        options: {
            floor: 0,
            ceil: 24,
            step: 1
        }
    };
thats it. it has several sliders, using the same steps you can use them.

Create Row every after 2 item in Angular ng-repeat - Ionic Grid/ tiles in ionic

Problem Statement:
i am having my elements which are to be shown in two column tiles. my data binding will be done dynamically from angular code behind. i can divide my row into columns but keeping data into that column in an ng-repeat is the challenge.

solution is simple, use angulars inbuilt variable $even of $index and show column for $index and $index+1 in column 1 and column 2 respectively.

for every even index 2 column will be set with $index and next elements and in odd index loop will not go in. problem solved. below is the sample code

Solution:
<div class="row" ng-repeat="sensors in SecurityDevices" ng-if="$even">
<div class="col col-49" >
<div class="imageIcon">
<img src="/img/devices/fire.png">
</div>
<div class="DeviceName">{{SecurityDevices[$index].Model}}</div>
<div class="FriendlyName">Kids Room</div>
</div>
<div class="col col-49" >
<div class="imageIcon">
<img src="/img/devices/motion.png">
</div>
<div class="DeviceName">{{SecurityDevices[$index+1].Model}}</div>
<div class="FriendlyName">Kids Room</div>
</div>
</div>

maintain two divs same width and height angular/ionic

Problem Statement:
I have two divs and i need to maintain them at some height always. one expands its size decreases based in dynamic content that will be loaded and  the other has to increase/decrease its height accordingly.

my elements are the below:
1. <div round-progress master
max="100"
current="100"
color="green"
bgcolor="#eaeaea"
rounded="true"
clockwise="true"
responsive="true">

</div>

2. 
<div class="item AirDivs AirMeterFill" ng-style="Airstyle">
      <div style="height:30%; background-color: rgba(195, 7, 15, 0.09);border-top: 3px solid     #DC0D29;font-size:smaller;text-align: center;">
<div>poor: 8</div>
<div></div>
</div>

</div>
according to size of 1st element i want to set height of 2nd element using angularJS/Ionic.

Solution:
It can be achieved through angular directives easily. Use below directive to set it

.directive('master',function () { //declaration
  function link(scope, element, attrs) { //scope we are in, element we are bound to, attrs of that element
   scope.$watch(function(){ //watch any changes to our element
 console.log("ht:"+element[0].offsetHeight);
     scope.Airstyle = { //scope variable style, shared with our controller
     height:element[0].offsetHeight-35+'px', //set the height in style to our elements height
     // width:element[0].offsetWidth+'px' //same with width
   };
   });
  }
 return {
  restrict: 'AE', //describes how we can assign an element to our directive in this case like <div master></div
  link: link // the function to link to our element
 };
});


  • i am having a directive called master which can be a element/attribute - defined by restrict
  • i am linking it using my link function, where i will be watching for any change of my master (1st element) 
  • when the height of master changes i am setting ng-style of  my other div.
  • i can get of height of 1st element using offsetHeight html property. 

Refrence: http://www.ngroutes.com/questions/1b1848d/set-height-of-one-div-to-another-div-in-angularjs.html

Saturday, 20 February 2016

$state.go problem in iOS9

there is a bug in web view in ios 9. $state.go is not working or sometimes screen flickers.

to resolve this a patch was released by the ionic team.
to use this:
1. add the js file at https://gist.github.com/IgorMinar/863acd413e3925bf282c in your index.html
2. add the depency to your module in app.js.
ex:
angular.module('starter', ['ionic','starter.controllers','starter.services','starter.modules','ngCordova','ngIOS9UIWebViewPatch'])
more info@ http://blog.ionic.io/ios-9-potential-breaking-change/

Opening other apps from your using cordova


  • Cordova uses UrlSchemes to open other apps.
  • URL schemes for ios and android will be different,

ex: for opening skype(lync), urlscheme for
           ios: lync:// or sip://
           android: com.microsoft.office.lync15

additionally to know the UrlScheme of an app for android you can look at the url of the app in google play store.
ex: https://play.google.com/store/apps/details?id=com.microsoft.office.lync15&hl=en

URL Schemes for some popular apps
ios android
sip:// or lync:// com.microsoft.office.lync15
yammer:// com.yammer.v1
twitter:// com.twitter.android
ms-outlook:// com.microsoft.office.outlook

for opening these apps, we have a good plugin called lampa: https://github.com/lampaa/com.lampa.startapp

to install the plugin use,
ionic plugin add com.lampa.startapp

to use the plugin use the following code:

if(device.platform === 'iOS') 
{
scheme = 'lync://';
}
else if(device.platform === 'Android')
{
scheme = 'com.microsoft.office.lync15';
}
navigator.startApp.start(scheme,function() { 
//alert("found 2013");
},
function() {  
$ionicPopup.alert({       
 template: "Please Install Lync",
 okType:'button-positive'
});
});

you can also do app availability check using it:
navigator.startApp.check("com.application.name", function(message) { /* success */
    console.log("app exists: "); 
    console.log(message.versionName); 
    console.log(message.packageName); 
    console.log(message.versionCode); 
    console.log(message.applicationInfo); 
}, 
function(error) { /* error */
    console.log(error);
});

additional details can be found in the github page.

additionally,
to allow other apps to open your app, you can define custom url scheme for your app:

ionic plugin add cordova-plugin-customurlscheme --variable URL_SCHEME=mycoolapp

mycoolapp:// is the url scheme of your app for ios.
if you want to do it manually, open xcodeproj file and add string URL Identifier in info.plist.
ex:


more details at: https://github.com/EddyVerbruggen/Custom-URL-scheme

for android:
add scheme in data node under activity->intent-filter.
<activity ....>
     <intent-filter>
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.DEFAULT" />
         <category android:name="android.intent.category.BROWSABLE" />
         <data android:scheme="myapp" />
     </intent-filter>
 </activity>

reference: http://www.telerik.com/blogs/how-to-use-custom-url-schemes

please comment if you have any queries/inputs.

set variables outside angular scope

if you need to assign to variables outside angular/ionic control, we need to use $apply function.

$scope.$apply(function() {
                          $scope.myFiles = userfiles;
 $scope.myFilesLength = $scope.myFiles.length;
                          });

this scenario came when i am doing the assignment in an callback function.

var AppControllers = angular.module('starter.controllers');

AppControllers
.controller('DownloadsPageCtrl',function($scope,$state,LDPServices,$cordovaDevice){
    //alert("in before enter downloads");
         
window.requestFileSystem(LocalFileSystem.PERSISTENT,0,function(fileSystem){
var FileStoredLoc = fileSystem.root.toURL()+"/LP/";
var dirEntry = fileSystem.root.getDirectory("LP",{create:true},gotDir);//fileSystem.root;
  }
}

function gotDir(dirEntry){
            //alert("direntry"+dirEntry);
            var dirReader = dirEntry.createReader();
            //alert("dirreader"+dirReader.readEntries);
            dirReader.readEntries(success,fail);

            }

function success(entries){
                //alert("succ:"+entries.length);
            //var AppDir = FileStoredLoc;//fileSystem.root.toURL()+"/LP/";
            var userfiles=[];
            for( i=0;i<entries.length;i++)
            {

            userfiles.push(entries[i].name);
           
            }
            //alert(userfiles.length);
            try
            {
            //var myf=["a.1","b.2"];
            //alert("b4");
            $scope.$apply(function() {
                          $scope.myFiles = userfiles;
 $scope.myFilesLength = $scope.myFiles.length;
                          });
           
            //alert("after");
            }
            catch(excp)
            {
$ionicPopup.alert({      
template: "Unable to open File" ,
okType:'button-positive'
});
            }
            }
html:
<ul class="list">
            <li ng-repeat="File in myFiles" class="item" ng-click="openFile(File)" ng-if="File != '.DS_Store'">
                {{File}}
            </li>
<div align="center" ng-if="myFilesLength == 0" style="color:white">
NO FILES TO BE SHOWN
</div>

        </ul>

download files using ionic/cordova

to download files using cordova, install filetransfer plugin

>ionic plugin add cordova-plugin-file-transfer

var fileTransfer = new FileTransfer();
fileTransfer.download(FileURL,StoragePath,function(storedurl){ //code goes here});

FileURL - path from which you need to download the file
StoragePath - storage location after download
function(storedurl) - function call back after downloaded & stored

access phone memory using ionic/cordova

for reading internal memory we need the below cordova plugin

1. cordova-plugin-file
to install
>ionic plugin add cordova-plugin-file

window.requestFileSystem(LocalFileSystem.PERSISTENT,0,function(fileSystem){
                                                 //alert("came"+fileSystem.root.toURL()+filename);

                                                 var FileStoredLoc = fileSystem.root.toURL();
}

requestFileSystem on succes returns FileSystem handler. using which you can refer any file/directory in the memory.
https://cordova.apache.org/docs/en/2.4.0/cordova/file/localfilesystem/localfilesystem.html

To find if a file/directory exists in phone memory:

window.resolveLocalFileSystemURL(FileORDirPath,Successhandler,Errorhandler);


directives in angularjs/ recognize click of a hyperlink in a dynamic text using angular JS

I will demonstrate use of directives using the example of recognizing a hyperlink click from a dynamic text.

About directives
To attach custom behavior to html, directives can be used. angular uses a lot of directives.
ng-model, ng-controller, ng-app are default directives provided by angular.

to learn more about directives read: https://docs.angularjs.org/guide/directive

syntax:
directive.js:
var AppControllers = angular.module('starter.controllers');


AppControllers
.directive('mylinkDir',function(LDPServices,$ionicPopup){
return{
           restrict:'A',//attribute
           scope:'true',
           link:function(scope,element,attrs){
           //your code goes here
           }
}

my-dire.html:
<div class="myClass" ng-repeat="myShorttext in myDetailsArray" mylink-dir>
    <p><a href="http://mycustomurl.com">link</a></p>
</div>

Basically i wanted to find clicks on hyperlinks in the div above. so i have attached a directive my div.
The text inside the div is dynamically coming i will not have control (for understanding purpose wrote a p and a inside the div).

Now, in link function i will find click on each element and filter for anchor clicks.
if(event.target.tagName.toLowerCase() === 'a')
{
   var ce = event.href;//gives me href of anchor and i do different actions based on url
}

i will have above if condition in my link function mylinkDir div. so all clicks will be detected and filters for anchors click.

in this kinds of scenario's directives comes handy.
scope of directive is throughout the app. so it can be used in any controller.
$scope will not be available inside a directive.

we can have directives in 4 levels.
E : Element
A : Attribute
C : Class // css class
M: Comment  //it can also recognize comments in code.

in angular2, ng-controllers are deprecated and use of directives encouraged for all the purposes.

please comment for any queries/suggestions.

Thursday, 10 December 2015

Enabling click to call and mail in android using ionic/cordova

by default in android tel and mailto are blocked in cordova/ionic.

to enable click to call/mail feature you can use one of below ways:

Option 1:

a. Install whitelist cordova plugin
       ionic plugin install cordova-plugin-whitelist
b.add the below lines to config.xml of your project
   <access origin="tel:*" launch-external="yes" />
   <access origin="mailto:*" launch-external="yes" />
now when you give your phone the below way, it will copy the number to dailing pad.
      <a href="tel:{{Contact.phone}}" style="margin-top: 10px;" class="button icon-left ion-ios-        telephone">{{Contact.phone}}</a>

Option 2:


$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|sip|chrome-extension):/);

add it in the app.js, dont forget to add $compileProvide dependency.