Install lamp on ubuntu14.04

By: Ryan Wong at

Here’s a list of steps to install lamp on a fresh server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sudo apt-get update
sudo apt-get install apache2
sudo apt-get install mysql-server php5-mysql

sudo mysql_install_db
sudo mysql_secure_installation

sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt

sudo nano /etc/apache2/mods-enabled/dir.conf

Add
<IfModule mod_dir.c>
DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
</IfModule>

sudo service apache2 restart

sudo apt-get install php5-package1 php5-package2 ...

ngCordova oauth Example with Linkedin

By: Ryan Wong at

I find most examples on the web are very barebone and nothing on linkedin Oauth. So heres an example with linkedin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Ctrl(scope, $cordovaOauth, oauthService){
$cordovaOauth.linkedin("clientKey", "clientSecret", [
"r_basicprofile",
"r_fullprofile",
"r_contactinfo",
"r_network",
"r_emailaddress"],
"csrf token you make").then(function(result) {
var access_token = result.access_token;
var expire_date = result.expires_in;
oauthService.getLinkedinProfile(access_token).then(function(result){
//do what you want
}, function(err){
//handle error
});
});
}

The oauthService is calling this url
https://api.linkedin.com/v1/people/~:(email-address,first-name,last-name)?format=json&oauth2_access_token=“ + access_token;

Hope this saves you time.

ngCordova Could not find InAppBrowser plugin Fix

By: Ryan Wong at

I found it very fustrating that they didn’t fix this bug yet.
When you installed the inappbrowser cordova plugin, you probably did the following:

1
cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser.git

In ngCordova.js, they hardcoded “org.apache.cordova.inappbrowser” when your plugin is called “cordova-plugin-inappbrowser”.

The solution is to strign replace all traces of “org.apache.cordova.inappbrowser” and everything should work fine.

Hope this saves you time.

Ionic Framework troubleshoot guide when working with android

By: Ryan Wong at

After developing my mobile app on the browser, I found many issues to arise when I started testing it on android.

I’m going to list all issues I encounter here for my reference in the future. IF this can help you save hours of work then thats good too.

##Issues

1.When using $http service in angular to do a POST request, it will wrap all form data in json and send it to the server.
If your backend is PHP(Node works fine), it won’t understand the json you send ot the server. The hack I found to fix this is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.config(function($httpProvider){
// Use x-www-form-urlencoded Content-Type
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';

/**
* The workhorse; converts an object to x-www-form-urlencoded serialization.
* @param {Object} obj
* @return {String}
*/

var param = function(obj) {
var query = '', name, value, fullSubName, subName, subValue, innerObj, i;

for(name in obj) {
value = obj[name];

if(value instanceof Array) {
for(i=0; i<value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value instanceof Object) {
for(subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value !== undefined && value !== null)
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}

return query.length ? query.substr(0, query.length - 1) : query;
};

// Override $http service's default transformRequest
$httpProvider.defaults.transformRequest = [function(data) {
return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
}];

});

2.When testing your mobile app in android, make sure to tunnel your server if your using localhost or a virtualhost hostname.
This stumped me for a while. I used ngrok to tunnel the port. If you have multiple virtualhost there maybe issues.
Maybe comment out the ones your not using.

3.When the spacing looks good in chrome, expect there to be less space in android. Try not to use position absolute stuff that are few pixels off
other elements.

4.Always use “ white-space: no-wrap;” for divs. For some reason android likes to wrap them.

5.If theres an error in the resolve function, it will crash hte page without warning. The usual cause of this kind of error is missing dependancy.

6.When using static images, make sure images are reference from “./“;

7.Local HTML5 videos don’t work properly in android. Just don’t do it. Just transform the video into gif and display it to save your sanity.
For videos that are external use the following script:

1
2
3
<video class="media-video" preload="auto" webkit-playsinline controls poster="./img/posterdefault.jpg">
<source type="video/mp4" ng-src="{{trustSrc(media.video)}}"></source>
</video>

I put a poster that matches the background of the page so it looks like the video just pops up and shows. Otherwise, you will see an ugly poster while it loads.
The video will always take time to load so you need the poster.

8.Make sure that each route you make has cache: false so when you navigate using href tags, it reloads the page from scratch or the page will look the way before navigating.

9.Failure [INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES]
This error means that you installed the apk from one machine and trying to install it with a different machine.
Delete the old app and create new one.

10.When using push notifications, make sure you add both ipv4 and ipv6 ips to google gcm.

  1. When using the command “transform:translateX(100%)” remember to use this instead on android “-webkit-transform:translate3d(100%,0,0)” .

12.What you see in browser is not how it will look in the emulator. What you see in emulator is not what you see in the device.

##Tips

1.Setting up Android environment on phone.

  • Turn on your phone
  • plugin your phone to your computer
  • Go to Settings
  • Go to Developer Options
  • Go to USB debugging and uncheck to check, it will ask you to verify your fingerprint
  • go to the terminal and type “adb devices -l” to see your device is connected
  • go to chrome hamburger -> More Tools -> Inspects Device
  • check your device is there
  • run

    1
    ionic platform add android
  • run

    1
    ionic run android --device

2.Dynamic Source for img and videos

  • if you need to put dynamic url into a video or image you have to sanitize it or chrome complains
    1
    2
    3
    4
    5
    function controller(scope, $sce){
    scope.trustSrc = function(src) {
    return $sce.trustAsResourceUrl(src);
    }
    }
1
<img ng-src="{{trustSrc(source))}}"/>

3.Screenshoting screen in android
Hold power button and down volume to screenshot

Push Notification With Laravel 4

By: Ryan Wong at

To Implement Push notification do the following:
add “davibennun/laravel-push-notification”: “dev-master” to your composer.json file

1
2
3
composer update davibennun/laravel-push-notification

php artisan config:publish davibennun/laravel-push-notification

Add the following to “app/config/app.php”

1
2
3
4
5
6
7
'providers' => array(
Davibennun\LaravelPushNotification\LaravelPushNotificationServiceProvider
)

'aliases' => array(
'PushNotification' => 'Davibennun\LaravelPushNotification\Facades\PushNotification'
)

Run the following:

1
php artisan config:publish davibennun/laravel-push-notification

Fill in your api key and you can now use your push notification for android.

##Common errors I recieved

  1. {“multicast_id”:XXXXXXXXXXXXXXXX,”success”:0,”failure”:1,”canonical_ids”:0,”results”:[{“error”:”MismatchSenderId”}]}
    Reason for this is becuase the sender id on the device is not a match to the api key on the server. The device Id is generated each time
    you register the push notification.

Angular filter to show how much time ago from a date object

By: Ryan Wong at

Here’s a good directive I found that formats a date object as time ago string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
function timeago() {
return function(input, p_allowFuture) {

var substitute = function (stringOrFunction, number, strings) {
var string = angular.isFunction(stringOrFunction) ? stringOrFunction(number, dateDifference) : stringOrFunction;
var value = (strings.numbers && strings.numbers[number]) || number;
return string.replace(/%d/i, value);
},
nowTime = (new Date()).getTime(),
date = (new Date(input)).getTime(),
//refreshMillis= 6e4, //A minute
allowFuture = p_allowFuture || false,
strings= {
prefixAgo: '',
prefixFromNow: '',
suffixAgo: "ago",
suffixFromNow: "from now",
seconds: "less than a minute",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years"
},
dateDifference = nowTime - date,
words,
seconds = Math.abs(dateDifference) / 1000,
minutes = seconds / 60,
hours = minutes / 60,
days = hours / 24,
years = days / 365,
separator = strings.wordSeparator === undefined ? " " : strings.wordSeparator,


prefix = strings.prefixAgo,
suffix = strings.suffixAgo;

if (allowFuture) {
if (dateDifference < 0) {
prefix = strings.prefixFromNow;
suffix = strings.suffixFromNow;
}
}

words = seconds < 45 && substitute(strings.seconds, Math.round(seconds), strings) ||
seconds < 90 && substitute(strings.minute, 1, strings) ||
minutes < 45 && substitute(strings.minutes, Math.round(minutes), strings) ||
minutes < 90 && substitute(strings.hour, 1, strings) ||
hours < 24 && substitute(strings.hours, Math.round(hours), strings) ||
hours < 42 && substitute(strings.day, 1, strings) ||
days < 30 && substitute(strings.days, Math.round(days), strings) ||
days < 45 && substitute(strings.month, 1, strings) ||
days < 365 && substitute(strings.months, Math.round(days / 30), strings) ||
years < 1.5 && substitute(strings.year, 1, strings) ||
substitute(strings.years, Math.round(years), strings);
// console.log(prefix+words+suffix+separator);
prefix.replace(/ /g, '')
words.replace(/ /g, '')
suffix.replace(/ /g, '')
return (prefix+' '+words+' '+suffix+' '+separator);

};
};

Hope this helps you out.

Dynamically add ng-click to dynamic html from scope variable

By: Ryan Wong at

Here’s my situation:

  1. I’m binding html to a scope variable.
  2. I’m going string replace some text in this scope variable.
  3. I’m going put in some directives into this scope variable while replacing.
  4. When I display my scope variable as html, I want all the new directives inside to work as expected.

Solution:

I found this awesome directive to accomplish this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function dynamic ($c) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$c(ele.contents())(scope);
});
}
};
}

angular.module('directives', [])
.directive('dynamic', ['$compile', dynamic]);

So here’s how my controller and html will look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function controller($scope){
$scope.content = 'blah blah <img src="whatever" alt="" /> blah';
var imageTag = new RegExp('<img .*alt="" />','g');
var srcTag = new RegExp('src=".*" alt','g');
$scope.imageList = $scope.content.match(imageTag);
if (!$scope.imageList){
$scope.imageList = [];
}
$scope.imageList = $scope.imageList.map(function(oneSrc){
$scope.content = $scope.content.replace(oneSrc,
oneSrc.replace('alt=""', ' alt="" ng-click="openCarousel()"'));
return oneSrc;
});

}
1
<div class="article-contents" dynamic="content"></div>

Hope this helps you out.