How can I make square-connect work with angularjs? - angularjs

Basing myself on the example provided by the SquareUp documentation (https://github.com/square/connect-api-examples.git). I am trying to integrate squareup to process payments with CC but I do not know what happens.
the view:
<div class="bg-light lter b-b wrapper-md">
<h1 class="m-n font-thin h3"></h1>
</div>
<div class="wrapper-md" >
<div class="row">
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading font-bold">CC info</div>
<div class="panel-body">
<div class="no-boot" ng-controller="PaymentController" ng-cloak>
<div id="successNotification" ng-show="isPaymentSuccess">
Card Charged Succesfully!!
</div>
<form novalidate id="payment-form" ng-hide="isPaymentSuccess">
<div id="card-errors" ng-repeat="error in card_errors">
<li>{{error.message}}</li>
</div>
<div>
<label>Card Number</label>
<div ng-model="data.card.card_number" id="sq-card-number"></div>
</div>
<div>
<label>CVV</label>
<div ng-model="data.card.cvv" id="sq-cvv"></div>
</div>
<div>
<label>Expiration Date</label>
<div ng-model="data.card.expiration_date" id="sq-expiration-date"></div>
</div>
<div>
<label>Postal Code</label>
<div ng-model="data.card.postal_code" id="sq-postal-code"></div>
</div>
<div>
<input ng-click="submitForm()" ng-disabled="isProcessing" type="submit" id="submit" value="Buy Now" class="btn btn-primary">
</div>
</form>
<button id="sq-apple-pay" class="button-apple-pay-block" ng-show="supportApplePay"></button>
</div>
</div>
</div>
</div>
</div>
</div>
the controller:
'use strict';
/* Controllers */
// signin controller
app.controller('PaymentController', ['$scope', '$http', function($scope, $http) {
//for showing #successNotification div
$scope.isPaymentSuccess = false;
//for disabling payment button
$scope.isProcessing = false;
//for disabling apple pay button
$scope.supportApplePay = false;
$scope.data = {
product_id: "001",
user: {},
card: {},
products: {
"001": {
"name": "Paper Origami 1:10,000 scale model (11 inch)",
"value":"1.0",
},
"002": {
"name": "Plastic 1:5000 scale model (22 inch)",
"value":"49.0",
},
"003": {
"name": "Metal & Concrete 1:1000 scale replica (9 feet)",
"value":"5000.0",
}
}
};
$scope.submitForm = function(){
console.log($scope.data)
$scope.isProcessing = true;
$scope.paymentForm.requestCardNonce();
return false
}
var cardNumber = $scope.data.card.card_number = 5409889944179029;
var cvv = $scope.data.card.cvv = 111;
var expirationDate = $scope.data.card.expirationDate = '02/21';
var postalCode = $scope.data.card.postalCode = 3311;
$scope.paymentForm = new SqPaymentForm({
applicationId: 'sandbox-sq0idp-IsHp4BXhhVus21G5JPyYpw',
locationId: 'CBASECJCvmqtoIL1fn3iReEjQRcgAQ',
inputClass: 'sq-input',
inputStyles: [
{
fontSize: '14px',
padding: '7px 12px',
backgroundColor: "transparent"
}
],
cardNumber: {
elementId: 'sq-card-number',
placeholder: '5409889944179029',
value: '5409889944179029'
},
cvv: {
elementId: 'sq-cvv',
placeholder: '111',
value: '111'
},
expirationDate: {
elementId: 'sq-expiration-date',
placeholder: '04/21',
value: '04/21'
},
postalCode: {
elementId: 'sq-postal-code',
placeholder: '33114',
value: '33114'
},
applePay: {
elementId: 'sq-apple-pay'
},
// cardNumber:''+cardNumber,
// cvv:''+cvv,
// expirationDate:''+expirationDate,
// postalCode:''+postalCode,
callbacks: {
cardNonceResponseReceived: function(errors, nonce, cardData) {
if (errors){
$scope.card_errors = errors
$scope.isProcessing = false;
$scope.$apply(); // required since this is not an angular function
}else{
$scope.card_errors = []
$scope.chargeCardWithNonce(nonce);
}
},
unsupportedBrowserDetected: function() {
// Alert the buyer
},
methodsSupported: function (methods) {
console.log(methods);
$scope.supportApplePay = true
$scope.$apply(); // required since this is not an angular function
},
createPaymentRequest: function () {
var product = $scope.data.products[$scope.data.product_id];
return {
requestShippingAddress: true,
currencyCode: "USD",
countryCode: "US",
total: {
label: product["name"],
amount: product["value"],
pending: false,
}
};
},
// Fill in these cases to respond to various events that can occur while a
// buyer is using the payment form.
inputEventReceived: function(inputEvent) {
switch (inputEvent.eventType) {
case 'focusClassAdded':
// Handle as desired
break;
case 'focusClassRemoved':
// Handle as desired
break;
case 'errorClassAdded':
// Handle as desired
break;
case 'errorClassRemoved':
// Handle as desired
break;
case 'cardBrandChanged':
// Handle as desired
break;
case 'postalCodeChanged':
// Handle as desired
break;
}
}
}
});
$scope.chargeCardWithNonce = function(nonce) {
alert("no");
var url = "libs/php_payment/process-card.php";
var data = {
nonce: nonce,
product_id: $scope.data.product_id,
name: $scope.data.user.name,
email: $scope.data.user.email,
street_address_1: $scope.data.user.street_address_1,
street_address_2: $scope.data.user.street_address_2,
city: $scope.data.user.city,
state: $scope.data.user.state,
zip: $scope.data.user.zip
};
$http.post(url, data).success(function(data, status) {
if (data.status == 400){
// display server side card processing errors
$scope.isPaymentSuccess = false;
$scope.card_errors = []
for (var i =0; i < data.errors.length; i++){
$scope.card_errors.push({message: data.errors[i].detail})
}
}else if (data.status == 200) {
$scope.isPaymentSuccess = true;
}
$scope.isProcessing = false;
}).error(function(){
$scope.isPaymentSuccess = false;
$scope.isProcessing = false;
$scope.card_errors = [{message: "Processing error, please try again!"}];
})
}
//build payment form after controller loads
var init = function () {
$scope.paymentForm.build()
};
init();
}]);
error: "Error: [$rootScope:inprog] $digest already in progress

I haven't done angular in a while, but I'm betting that your issue is in:
methodsSupported: function (methods) {
console.log(methods);
$scope.supportApplePay = true
$scope.$apply(); // required since this is not an angular function
},
You are calling $apply() after a non-asyc call, generally you apply new data that you got asynchronously. See Angular Docs

Related

How to pass JSON Array {{this.row}} to submit() function to get posted using Axios.post

this.row is Generating form input into JSON Array which I'm trying to post via submit function using Axios but unable to the value please help what's wrong ??
Axios postcode
axios.post('/submit', this.rows).then(response => {
this.rows; //Clear input fields.
this.loaded = true;
Here is my complete code
<template>
<form #submit.prevent="submit">
{{ /* These are 3 buttons which are calling 3 different function to create input boxes */ }}
<div class="d-flex mt-5"><div>
<label>Add A</label>
<button type="button" #click="addRow">01</button>
</div>
<div> <label>Add B</label>
<button type="button" #click="addRow1">02</button>
</div>
<div> <label>Add c</label>
<button type="button" #click="addRow3">03</button>
</div>
</div>
{{ /* this section calls button-counter template from script code */ }}
<div v-for="row in rows" :key="row.id">
<button-counter :name ="row.name" :id="row.id" :value.sync="row.value"></button-counter>
</div>
<div>
<button type="submit" class="btn btn-primary">Add Points</button>
</div>
<div v-if="success" class="alert alert-success mt-3">
Message sent!
</div>
</form>
</template>
<script>
Vue.component("button-counter", {
props: {
value: {
default: "",
}
},
/* This is my template which gets called fro the addition of new inputs ...guess here I need to add v-model so that dynamically generated fields will be posted but I'm unable to get it posted */
template: '<input class="form-control" id= id.row name=row.name type="number" style="margin-top: 10px;" :value="value" #change="$emit(\'update:value\', $event.target.value)">'
});
export default {
props: ['gameId','userId'],
mounted() {
console.log('Component mounted.')
},
data() {
return {
gamex: this.gameId,
rows: [],
count: 0,
fields: {},
errors: {},
success: false,
loaded: true,
};
},
computed: {
total() {
if (this.rows.length) {
return this.rows.reduce((acc, row) => acc += parseInt(row.value), 0);
}
return 0;
}
},
methods: {
addRow: function() {
var txtCount = 1;
let id = "txt_" + txtCount;
this.rows.push({ name:'zero',value:100, description: "textbox1", id });
},
addRow1: function() {
var txtCount = 1;
let id = "txt2_" + txtCount;
this.rows.push({name:'one',value:200, description: "textbox2", id });
},
addRow3: function() {
var txtCount = 1;
let id = "txt3_" + txtCount;
this.rows.push({name:'two',value:300, description: "textbox3", id });
},
submit: function() {
if (this.loaded) {
this.loaded = false;
this.success = false;
this.errors = {};
axios.post('/submit', this.rows).then(response => {
this.rows; //Clear input fields.
this.loaded = true;
this.success = true;
}).catch(error => {
this.loaded = true;
if (error.response.status === 422) {
this.errors = error.response.data.errors || {};
}
});
}
},
followUser() {
axios.post('/chklet/' + this.userId)
.then(response => {
return response.data ;
});
}
},
mounted () {
this.followUser();
}
};
</script>
You can use JSON.stringify(array_to_convert_in_string_to_send_in_ajax) but you will have to json_decode it also in backend server
In server section for example laravel:
$result = json_decode($request->your_array);

How to display repeated drop down based on button selection in AngularJS

I need to display a drop down along with Plus button at first time. Based on button click it should display one more combination , I mean same drop down with options excluded previous selected value which we have from the first drop down and the plus button. This action should be repeat based on plus button selection.
Here is my code:
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.init = function() {
$scope.display = false;
};
$scope.init();
$scope.records = [
{ id: "part1", part: "Frt Bumper Cover" },
{ id: "part2", part: "Frt Lwr Bumper Cover" },
{ id: "part3", part: "Frt Upr Bumper Cover" },
{ id: "part4", part: "Hood Panel" },
];
$scope.changedValue = function(key) {
// alert(key);
//var index = $scope.records.indexOf(item);
//alert(index);
$scope.records.splice(index, 1);
//delete $scope.records[key];
// alert(JSON.stringify($scope.records));
};
$scope.sample = function() {
$scope.display = true;
// alert("sample: "+$scope.display);
//alert("inside sample:::"+JSON.stringify($scope.records));
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl" ng-init="init()">
<div>
<select ng-model="selectedRecord"
ng-change="changedValue(selectedRecord)"
ng-options="record.id as record.part for record in records">
<option ng-repeat="x in records">{{x.part}}</option>
</select>
<input type="submit" value="+" ng-show="records.length!=1"
ng-click="sample()" />
</div>
<div ng-show="display">
<select ng-model="selectedRecord"
ng-change="changedValue(selectedRecord)"
ng-options="record.id as record.part for record in records">
</select>
<input type="submit" value="+" ng-show="records.length!=1"
ng-click="sample()" />
</div>
</body>
I am unable to display like that, please share your ideas to do this
My friend, i think i have a solution for your problem. :D
Its very basic code i think, so i would be happy to explain more in depth if needed.
look code here: plnkr, this is basically all the code, so its my first plunker.
$scope.originalRecords = [
{ id: "part1", part: "Frt Bumper Cover" },
{ id: "part2", part: "Frt Lwr Bumper Cover" },
{ id: "part3", part: "Frt Upr Bumper Cover" },
{ id: "part4", part: "Hood Panel" },
];
$scope.selectArray = [{selectedOption: null, options: $scope.originalRecords}];
$scope.selectedOption =[];
$scope.hideButton = false;
$scope.addNewSelect = function (arrayToSearch, selectedOption) {
var index = arrayToSearch.map(function(d) { return d['part'];}).indexOf(selectedOption);
var newRecords = arrayToSearch.slice();
newRecords.splice(index, 1);
if (newRecords.length > 0) {
$scope.selectArray.push({selectedOption: null, options: newRecords});
} else {
$scope.hideButton = true;
}
}
Hope it helps.

v-for and computed properties calling methods

I'm trying to update some properties on a VueJS object list, but I'm having some glitches.
Here's the HTML:
<div id="el">
<p>Total Chats: {{ chats.length }} ({{ unreadCount }} unread)</p>
<button v-on:click="__addChat(true)">Add a Chat</button>
<button v-on:click="__makeAllRead">Read All</button>
<pre>{{ $data | json }}</pre>
<ul>
<li v-for="chat in chats">
<p>
Message {{ chat.id }}
<span v-if="chat.unread"><strong>(UNREAD)</strong></span>
</p>
</li>
</ul>
</div>
And the Vue code:
var vm = new Vue({
el: '#el',
data: {
nextID : 2,
chats: {
'6fc5gh4j3kl_FIRST': {
id : 1,
unread : true,
body : Date(),
}
},
},
methods: {
__addChat: function (unread) {
var chat = {
id : this.nextID++,
unread : unread,
body : Date(),
};
this.chats[this.__makeHash()] = chat;
console.log(this.chats);
},
__makeAllRead : function() {
console.log(Object.keys(this.chats));
for ( var key in Object.keys(this.chats) ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) ) {
this.chats[key] = true;
}
}
},
__countUnread : function() {
var unread = 0;
for ( var key in Object.keys(this.chats) ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) && this.chats[key].unread ) {
unread++;
}
}
return unread;
},
__makeHash: function() {
return '6fc5gh4j3kl1AZ0' + Math.floor((Math.random() * 100) + 1);
},
},
ready: function() {
this.__addChat(false);
},
computed: {
unreadCount: function () {
console.log('counting...');
return this.countUnread();
}
}
});
Here's a Fiddle: http://jsfiddle.net/522aw2n5/7/
Things I cannot understand/fix on this code:
1) A computed property using a method to update the count
2) It displays only the object manually created, not the dynamically ones.
3) I cannot make all messages read by clicking a button.
This is Vue 1.0.0 RC2.
Could you, please, tell me what Am I doing wrong?
Answered on VueJS's Gitter
HTML
<div id="el">
<p>Total Chats: {{ totalChats }} ({{ unreadCount }} unread)</p>
<button v-on:click="__addChat(true)">Add a Chat</button>
<button v-on:click="__makeAllRead">Read All</button>
<pre>{{ $data | json }}</pre>
<ul>
<li v-for="chat in chats">
<p>
{{ chat.id }}
<span v-if="chat.unread"><strong>(UNREAD)</strong></span>
</p>
</li>
</ul>
</div>
Vue Code
var vm = new Vue({
el: '#el',
data: {
nextID : 2,
chats: {
'6fc5gh4j3kl_FIRST': {
id : 1,
unread : true,
body : Date(),
}
},
},
methods: {
__addChat: function (unread) {
var chat = {
id : this.nextID++,
unread : unread,
body : Date(),
};
this.$set('chats.' + this.__makeHash(), chat);
},
__makeAllRead : function() {
console.log(Object.keys(this.chats));
for ( var key in this.chats ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) ) {
this.chats[key].unread = false;
}
}
},
__makeHash: function() {
return 'fc5gh4j3kl1AZ0' + Math.floor((Math.random() * 100) + 1);
},
},
ready: function() {
this.__addChat(false);
},
computed: {
totalChats: function() {
var size = 0, key;
for (key in this.chats) {
if (this.chats.hasOwnProperty(key)) size++;
}
return size;
},
unreadCount: function () {
var unread = 0;
for ( var key in this.chats ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) && this.chats[key].unread ) {
unread++;
}
}
return unread;
}
}
});

How to Keep track of all clicks on page in ionic application?

I have created simple page which contains check boxes. On this page user can check and uncheck boxes multiple times. I want to keep track of all these events? How Can I do that?
here is my code.
app.js
var pmApp = angular.module('pmApp', ['ionic']);
pmApp.controller('CheckboxController', function($scope) {
$scope.devList = [
{ text: "Device & app history", details : "Allows the app to view one or more of: information about activity on the device, which apps are running, browsing history and bookmarks" ,checked: true },
{ text: "Identity", details: "Uses one or more of: accounts on the device, profile data", checked: false },
{ text: "Calendar", details: "Uses calendar information", checked: false },
{ text: "Contact", details: "Uses contact information", checked: false },
{ text: "Location", details: "Uses the device's location", checked: false },
{ text: "SMS", details: "Uses one or more of: SMS, MMS. Charges may apply.", checked: false }
];
$scope.selection=[];
// toggle selection for a given employee by name
$scope.toggleSelection = function toggleSelection(item) {
var idx = $scope.selection.indexOf(item);
// is currently selected
if (idx > -1) {
$scope.selection.splice(idx, 1);
}
// is newly selected
else {
$scope.selection.push(item);
}
};
});
index.html
<div class="list" ng-controller="CheckboxController">
<ion-checkbox ng-repeat="item in devList"
ng-model="item.checked"
ng-checked="selection.indexOf(item) > -1"
ng-click="toggleSelection(item)"
>
{{ item.text }}
<h3 class="item-text-wrap"> {{ item.details }}</h3>
</ion-checkbox>
<div class="item">
<pre ng-bind="selection | json"></pre>
</div>
</div>
Thanks in advance, any help would be appreciated.
Regards
You can use https://docs.angularjs.org/api/ng/directive/ngMouseover to make a counter for mouse hovers on all your elements: and then use
https://docs.angularjs.org/api/ng/directive/ngClick to record clicks and https://docs.angularjs.org/api/ng/directive/ngMousemove to record the mouse being moved and get the position:
Everything Used:
ng-click
ng-dblclick
ng-mousedown
ng-mouseup
ng-mouseenter
ng-mouseleave
ng-mousemove
ng-mouseover
Here is some example code:
HTML:
<body ng-app="mainModule">
<div ng-controller="mainController">
<h3>1. Click</h3>
<button id="firstBtn" ng-click="onFirstBtnClick()">Click me</button>
<strong>RESULT:</strong> {{onFirstBtnClickResult}}<br />
<br />
<h3>2. Click with Dependency Injection</h3>
<label>Type something: <input type="text" ng-model="secondBtnInput"></label>
<button id="secondBtn" ng-click="onSecondBtnClick(secondBtnInput)">Click me</button><br />
<strong>RESULT:</strong> {{onSecondBtnClickResult}}<br />
<br />
<h3>3. Double click</h3>
Double-click the square<br />
<img src="images/square.png" ng-dblclick="onDblClick()" /><br />
<strong>RESULT:</strong> {{onDblClickResult}}<br />
<h3>4. Mouse down, up, enter, leave, move, over</h3>
Move the mouse on the square<br />
<img src="images/square.png"
ng-mousedown="onMouseDown($event)"
ng-mouseup="onMouseUp($event)"
ng-mouseenter="onMouseEnter($event)"
ng-mouseleave="onMouseLeave($event)"
ng-mousemove="onMouseMove($event)"
ng-mouseover="onMouseOver($event)" /><br />
<strong>MOUSE DOWN RESULT:</strong> {{onMouseDownResult}}<br />
<strong>MOUSE UP RESULT:</strong> {{onMouseUpResult}}<br />
<strong>MOUSE ENTER RESULT:</strong> {{onMouseEnterResult}}<br />
<strong>MOUSE LEAVE RESULT:</strong> {{onMouseLeaveResult}}<br />
<strong>MOUSE MOVE RESULT:</strong> {{onMouseMoveResult}}<br />
<strong>MOUSE OVER RESULT:</strong> {{onMouseOverResult}}
</div>
</body>
</html>
JS
angular.module("mainModule", [])
.controller("mainController", function ($scope)
{
// Initialization
$scope.onFirstBtnClickResult = "";
$scope.secondBtnInput = "";
$scope.onDblClickResult = "";
$scope.onMouseDownResult = "";
$scope.onMouseUpResult = "";
$scope.onMouseEnterResult = "";
$scope.onMouseLeaveResult = "";
$scope.onMouseMoveResult = "";
$scope.onMouseOverResult = "";
// Utility functions
// Accepts a MouseEvent as input and returns the x and y
// coordinates relative to the target element.
var getCrossBrowserElementCoords = function (mouseEvent)
{
var result = {
x: 0,
y: 0
};
if (!mouseEvent)
{
mouseEvent = window.event;
}
if (mouseEvent.pageX || mouseEvent.pageY)
{
result.x = mouseEvent.pageX;
result.y = mouseEvent.pageY;
}
else if (mouseEvent.clientX || mouseEvent.clientY)
{
result.x = mouseEvent.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
result.y = mouseEvent.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
if (mouseEvent.target)
{
var offEl = mouseEvent.target;
var offX = 0;
var offY = 0;
if (typeof(offEl.offsetParent) != "undefined")
{
while (offEl)
{
offX += offEl.offsetLeft;
offY += offEl.offsetTop;
offEl = offEl.offsetParent;
}
}
else
{
offX = offEl.x;
offY = offEl.y;
}
result.x -= offX;
result.y -= offY;
}
return result;
};
var getMouseEventResult = function (mouseEvent, mouseEventDesc)
{
var coords = getCrossBrowserElementCoords(mouseEvent);
return mouseEventDesc + " at (" + coords.x + ", " + coords.y + ")";
};
// Event handlers
$scope.onFirstBtnClick = function () {
$scope.onFirstBtnClickResult = "CLICKED";
};
$scope.onSecondBtnClick = function (value) {
$scope.onSecondBtnClickResult = "you typed '" + value + "'";
};
$scope.onDblClick = function () {
$scope.onDblClickResult = "DOUBLE-CLICKED";
};
$scope.onMouseDown = function ($event) {
$scope.onMouseDownResult = getMouseEventResult($event, "Mouse down");
};
$scope.onMouseUp = function ($event) {
$scope.onMouseUpResult = getMouseEventResult($event, "Mouse up");
};
$scope.onMouseEnter = function ($event) {
$scope.onMouseEnterResult = getMouseEventResult($event, "Mouse enter");
};
$scope.onMouseLeave = function ($event) {
$scope.onMouseLeaveResult = getMouseEventResult($event, "Mouse leave");
};
$scope.onMouseMove = function ($event) {
$scope.onMouseMoveResult = getMouseEventResult($event, "Mouse move");
};
$scope.onMouseOver = function ($event) {
$scope.onMouseOverResult = getMouseEventResult($event, "Mouse over");
};
});
You could try with the newest Ionic Analytics, if that will suit your needs. More info on their official blog post: http://docs.ionic.io/v1.0/docs/analytics-from-scratch.
Usage is pretty straight forward (from the additional docs):
.controller('MyCtrl', function($ionicAnalytics) {
$ionicAnalytics.track('Purchase Item', {
item_id: 'lpdsx,
item_name: 'Leopard Socks'
});
});

Occasional AngularJS error when directive is compiling

I have an AngularJS directive that renders into a custom social share widget. Out of about 10,000 page views per day, around 1 or 2 of those times, Angular errors out after starting to compile the directive. This leaves the raw HTML partial in the DOM, visible to the user.
I only came to know of this error because it was reported by several users. I can't reproduce it, but I have devised some informative logging which shows that it is occurring.
Each time this has occurred:
Browser is always Chrome
OS is Mac or Windows
Angular starts the compile phase, but fails before starting post link
Angular reports an error during the compile phase, but the 'exception' object passed to the '$exceptionHandler' service is always null.
No other JavaScript errors are reported
This error is occurring for some of the same IPs across multiple days.
Has anyone out there had a similar issue?
Edit
Here's my code...
JavaScript:
(function () {
angular.module('common', []);
angular.module('common')
.filter('encodeURIComponent', function () {
return window.encodeURIComponent;
});
function configure($provide) {
// Pass all Angular errors to Loggly
$provide.decorator("$exceptionHandler", function ($delegate) {
return function exceptionHandlerDecorator(exception, cause) {
$delegate(exception, cause);
_LTracker.push({
'error': 'angularError',
'app': 'shareCounts',
'err': exception,
'element': cause
});
};
});
}
angular.module('common')
.config(['$provide', configure]);
function configure($provide) {
// Defines available share options as well as behaviors of the share popup windows
function shareLinksConfig() {
return {
'facebook': {
width: 670,
height: 200,
urlBase: 'https://www.facebook.com/sharer/sharer.php?',
shareParamPre: 'u=',
msgParamPre: '',
mediaParamPre: '',
addParams: ''
},
'twitter': {
width: 550,
height: 420,
urlBase: 'https://twitter.com/intent/tweet?',
shareParamPre: 'url=',
msgParamPre: '&text=',
mediaParamPre: ''
},
'googlePlus': {
width: 600,
height: 600,
urlBase: 'https://plus.google.com/share?',
shareParamPre: 'url=',
msgParamPre: '',
mediaParamPre: '',
addParams: ''
},
'linkedIn': {
width: 600,
height: 400,
urlBase: 'http://www.linkedin.com/shareArticle?',
shareParamPre: 'url=',
msgParamPre: '',
mediaParamPre: '',
addParams: '&mini=true'
},
'pinterest': {
width: 750,
height: 320,
urlBase: 'https://www.pinterest.com/pin/create/button/?',
shareParamPre: 'url=',
msgParamPre: '&description=',
mediaParamPre: '&media=',
addParams: ''
},
'email': {
width: 0,
height: 0,
urlBase: '',
shareParamPre: '',
msgParamPre: '',
mediaParamPre: '',
addParams: ''
}
};
}
$provide.factory('shareLinksConfig', shareLinksConfig);
}
angular.module('common')
.config(['$provide', configure]);
function ShareLinksController($scope, shareLinksService) {
sendToLoggly.push("A \"ShareLinksController\" started constructing...");
sendToLoggly.push("...and the $scope is typeof...");
sendToLoggly.push(typeof $scope);
var vm = this;
vm.share = function ($event, shareVia) {
if (shareVia !== 'email') {
$event.preventDefault();
// console.log($scope.mediaUrl);
shareLinksService.openPopUp(shareVia, $scope.shareUrl, $scope.shareMsg, $scope.mediaUrl);
}
// Tell Google Analytics share link was clicked
shareLinksService.pushGAEvent($scope.analyticsLocation, shareVia, $scope.shareUrl);
};
$scope.shareLinksShown = true; // Initialized to true, but then this gets set to false in the directive's link function if slideIn is true
vm.toggle = function ($event) {
$event.preventDefault();
$scope.shareLinksShown = !$scope.shareLinksShown;
};
sendToLoggly.push("...and controller finished constructing.");
}
angular.module('common')
.controller('ShareLinksController', ["$scope", "shareLinksService",
ShareLinksController]);
function fuShareLinks($http, shareLinksConfig, testRenderingService) {
function compile() {
sendToLoggly.push("A \"fuShareLinks\" directive started compiling...");
testRenderingService.testShareCounts();
return function postLink(scope) {
sendToLoggly.push("A \"fuShareLinks\" directive started postLinking...");
function Settings(shareVia, slideInDir, slideToggleLabel, colorized, showCounts) {
var self = this,
prop,
splitArray;
/* --------
ShareVia
--------
Comma separated list of ways to share
Accepted options are: 'facebook, twitter, googlePlus, linkedIn, pinterest, email' */
// Copy the properties from the config and initialize to false
self.shareVia = {};
for (prop in shareLinksConfig) {
if (shareLinksConfig.hasOwnProperty(prop)) {
self.shareVia[prop] = false;
}
}
if (typeof shareVia === 'string') {
splitArray = shareVia.split(',');
} else {
splitArray = [];
}
// Check each value of splitArray, if it is in possible share options,
// set that option to true.
angular.forEach(splitArray, function (value) {
// Clean up 'value' a bit by removing spaces
value = value.trim();
if (value.length > 0) {
if (self.shareVia.hasOwnProperty(value)) {
self.shareVia[value] = true;
}
}
});
/* --------
Slide In
--------
The slide-in functionality is activated by passing a value to 'slideInDir'.
Accepted values are 'left' or 'down' (case insensitive)
The 'slideToggleLabel' can be any string, if empty, it defaults to 'Share'. */
self.slideIn = {
direction: '',
label: 'Share'
};
if (typeof slideInDir === 'string') {
slideInDir = slideInDir.toUpperCase();
}
switch (slideInDir) {
case 'LEFT':
self.slideIn.direction = 'left';
break;
case 'DOWN':
self.slideIn.direction = 'down';
break;
}
if (typeof slideToggleLabel === 'string') {
self.slideIn.label = slideToggleLabel;
}
/* ---------
Colorized
---------
'true', 'yes', or 'colorized' (case insensitive) -- results in true
defaults to false */
self.colorized = false;
if (typeof colorized === 'string') {
colorized = colorized.toUpperCase();
}
switch (colorized) {
case 'TRUE':
self.colorized = true;
break;
case 'YES':
self.colorized = true;
break;
case 'COLORIZED':
self.colorized = true;
break;
}
/* -----------
Show Counts
-----------
'true', 'yes', or 'show' (case insensitive) -- results in true
defaults to false */
self.showCounts = false;
if (typeof showCounts === 'string') {
showCounts = showCounts.toUpperCase();
}
switch (showCounts) {
case 'TRUE':
self.showCounts = true;
break;
case 'YES':
self.showCounts = true;
break;
case 'SHOW':
self.showCounts = true;
break;
}
}
scope.settings = new Settings(
scope.shareVia,
scope.slideInDir,
scope.slideToggleLabel,
scope.colorized,
scope.showCounts
);
// Initally hide the share links, if they are set to toggle
if (scope.settings.slideIn.direction !== '') {
scope.shareLinksShown = false;
}
function ShareCounts(shareVia) {
var self = this;
angular.forEach(shareVia, function (value, name) {
self[name] = 0;
});
$http.get(
'/local/social-share-counts/?url=' +
encodeURIComponent(scope.shareUrl)
).success(function (data) {
/* Check for share counts in the returned data.
Must use consistent naming for the social networks
from shareLinksConfig properties all the way to the
JSON data containting the counts.
Expected JSON format:
{
"twitter": {
"count": 42,
"updated": "2015-03-25T15:13:48.355422"
},
"facebook": {
"count": 120,
"updated": "2015-03-25T15:13:47.470778"
}
}
*/
angular.forEach(shareVia, function (value, name) {
if (data[name] && data[name]["count"]) {
self[name] = data[name]["count"];
}
});
}).error(function (data, status) {
sendToLoggly.push("HTTP Response " + status);
});
}
// If showing share counts, get the counts from the specified networks
if (scope.settings.showCounts) {
scope.shareCounts = new ShareCounts(scope.settings.shareVia);
}
sendToLoggly.push("...and directive finished postLinking.");
};
sendToLoggly.push("...and directive finished compiling.");
}
return {
restrict: 'E',
scope: {
shareVia: '#',
shareUrl: '#',
shareMsg: '#',
mediaUrl: '#',
analyticsLocation: '#',
slideInDir: '#',
slideToggleLabel: '#',
colorized: '#',
showCounts: '#'
},
controller: 'ShareLinksController',
controllerAs: 'shrLnksCtrl',
templateUrl: '/angular-partials/common.share-links.html',
compile: compile
};
}
angular.module('common')
.directive('fuShareLinks', ['$http', 'shareLinksConfig', 'testRenderingService', fuShareLinks])
.factory('testRenderingService', function () {
var timerId = null;
function evalShareRender() {
var renderError = (-1 < $('em.ng-binding')
.text()
.indexOf('{{'));
if (renderError) {
console.error('RENDER ERROR');
_LTracker.push({
'error': 'rendering',
'app': 'shareCounts',
'statusMsgs': sendToLoggly,
'userAgent': navigator.userAgent
});
}
}
return {
testShareCounts: function () {
if (!timerId) {
timerId = window.setTimeout(evalShareRender, 5000);
}
}
};
});
function shareLinksService(shareLinksConfig) {
function openPopUp(shareVia, shareUrl, shareMsg, mediaUrl) {
var width,
height,
urlBase,
shareParamPre,
msgParamPre,
mediaParamPre,
addParams,
popUpUrl;
width = shareLinksConfig[shareVia].width;
height = shareLinksConfig[shareVia].height;
urlBase = shareLinksConfig[shareVia].urlBase;
shareParamPre = shareLinksConfig[shareVia].shareParamPre;
msgParamPre = shareLinksConfig[shareVia].msgParamPre;
mediaParamPre = shareLinksConfig[shareVia].mediaParamPre;
addParams = shareLinksConfig[shareVia].addParams;
popUpUrl = encodeURI(urlBase);
popUpUrl += encodeURI(shareParamPre);
popUpUrl += encodeURIComponent(shareUrl);
if (msgParamPre && shareMsg) {
popUpUrl += encodeURI(msgParamPre);
popUpUrl += encodeURIComponent(shareMsg);
}
if (mediaParamPre && mediaUrl) {
popUpUrl += encodeURI(mediaParamPre);
popUpUrl += encodeURIComponent(mediaUrl);
}
popUpUrl += encodeURI(addParams);
// Open the social share window
window.open(popUpUrl, '_blank', 'width=' + width + ',height=' + height);
}
function pushGAEvent(analyticsLocation, shareVia, shareUrl) {
function capitalize(firstLetter) {
return firstLetter.toUpperCase();
}
var gaEventAction = shareVia;
gaEventAction = gaEventAction.replace(/^[a-z]/, capitalize);
gaEventAction += ' - Clicked';
_gaq.push([
'_trackEvent',
analyticsLocation + ' - SocialShare',
gaEventAction,
shareUrl
]);
}
return {
openPopUp: openPopUp,
pushGAEvent: pushGAEvent
};
}
angular.module('common')
.factory('shareLinksService', ['shareLinksConfig', shareLinksService]);
}());
HTML:
<div class="share-links-wrapper" ng-class="{ 'right': settings.slideIn.direction === 'left', 'center': settings.slideIn.direction === 'down' }" ng-cloak>
<a href="#" class="toggle" ng-show="settings.slideIn.direction != ''" ng-click="shrLnksCtrl.toggle($event)">
<i class="fuicon-share"></i>{{ settings.slideIn.label }}
</a>
<div class="share-links" ng-class="{ 'share-links-colorized': settings.colorized }" ng-show="shareLinksShown">
<ul>
<li ng-show="settings.shareVia.facebook">
<a href="#" ng-click="shrLnksCtrl.share($event, 'facebook')"
class="fuicon-hex-facebook">
</a>
<em ng-show="settings.showCounts && shareCounts.facebook > 0">
{{ shareCounts.facebook }}
</em>
</li>
<li ng-show="settings.shareVia.twitter">
<a href="#" ng-click="shrLnksCtrl.share($event, 'twitter')"
class="fuicon-hex-twitter">
</a>
<em ng-show="settings.showCounts && shareCounts.twitter > 0">
{{ shareCounts.twitter }}
</em>
</li>
<li ng-show="settings.shareVia.googlePlus">
<a href="#" ng-click="shrLnksCtrl.share($event, 'googlePlus')"
class="fuicon-hex-googleplus">
</a>
<em ng-show="settings.showCounts && shareCounts.googlePlus > 0">
{{ shareCounts.googlePlus }}
</em>
</li>
<li ng-show="settings.shareVia.linkedIn">
<a href="#" ng-click="shrLnksCtrl.share($event, 'linkedIn')"
class="fuicon-hex-linkedin">
</a>
<em ng-show="settings.showCounts && shareCounts.linkedIn > 0">
{{ shareCounts.linkedIn }}
</em>
</li>
<li ng-show="settings.shareVia.pinterest && mediaUrl">
<a href="#" ng-click="shrLnksCtrl.share($event, 'pinterest')"
class="fuicon-hex-pinterest">
</a>
<em ng-show="settings.showCounts && shareCounts.pinterest > 0">
{{ shareCounts.pinterest }}
</em>
</li>
<li ng-show="settings.shareVia.email">
<a href="mailto:?subject={{ shareMsg | encodeURIComponent }}
&body={{ shareUrl | encodeURIComponent }}"
ng-click="shrLnksCtrl.share($event, 'email')"
class="fuicon-hex-email">
</a>
</li>
</ul>
</div>
</div>
Not had such an issue, but as its so infrequent could you make it reload the page?
Also, do you know about ng-cloak? it can be useful to hide the raw stuff :)
Could it be a race condition?

Resources