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

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'
});
});

Related

React-share. Throws error TypeError: Super expression must either be null or a function, not undefined when trying to use it in require

I am new in ReactJs and trying to learn it. I installed a package of react-share. Since i am trying to edit someone else's code i am not able to import the package due to webpack I believe. Every time i try to import a package I receive an error saying the import should always be on top of the script. I tried using require and I get this error in Console
TypeError: Super expression must either be null or a function, not undefined
My code looks like this:
"use strict";
require('./../../../assets/styles/components/thread.less');
var reactShare = require('react-share');
var React = require('react');
var ReactDOM = require('react-dom');
var Fluxxor = require('fluxxor');
var _ = require("lodash");
var FluxMixin = Fluxxor.FluxMixin(React);
var StoreWatchMixin = Fluxxor.StoreWatchMixin;
var routerShape = require('react-router').routerShape;
var MicroAudioViews = require('./../../constants/MicroAudioViews');
var AudioModes = require("./../../constants/AudioModes");
var i18n = require("i18next-client");
//components
var AudioVisualizer = require('../elements/AudioVisualizer');
var ReviewOverlay = require('../elements/ReviewOverlay');
var ReviewShare = require('../elements/ReviewShare');
var Menu = require('../elements/Menu');
I have to use react-share's
<FacebookShareButton url={shareLink} quote={title} className="social-media-icon">
<FacebookIcon size={32} round />
</FacebookShareButton>`
Component to share the shareLink on facebook.
Here the full code.
/*import {
FacebookShareButton,
GooglePlusShareButton,
TwitterShareButton,
WhatsappShareButton,
FacebookIcon,
TwitterIcon,
WhatsappIcon
} from 'react-share';*/
"use strict";
require('./../../../assets/styles/components/thread.less');
var reactShare = require('react-share');
var React = require('react');
var ReactDOM = require('react-dom');
var Fluxxor = require('fluxxor');
var _ = require("lodash");
var FluxMixin = Fluxxor.FluxMixin(React);
var StoreWatchMixin = Fluxxor.StoreWatchMixin;
var routerShape = require('react-router').routerShape;
var MicroAudioViews = require('./../../constants/MicroAudioViews');
var AudioModes = require("./../../constants/AudioModes");
var i18n = require("i18next-client");
//components
var AudioVisualizer = require('../elements/AudioVisualizer');
var ReviewOverlay = require('../elements/ReviewOverlay');
var ReviewShare = require('../elements/ReviewShare');
var Menu = require('../elements/Menu');
var Review = React.createClass({
mixins:[
FluxMixin,
StoreWatchMixin("ThreadStore", "RecordStore", "ReviewStore", "ApplicationStore", "SyncStore", "DemoStore", "ShareStore")
],
contextTypes: {
router: routerShape.isRequired
},
/* react interface*/
getInitialState: function() {
var selectedThreads = [];
var shareType = 'thread';
if(this.props.location.state && this.props.location.state.type == "thread") {
selectedThreads.push(this.props.location.state.threadId);
} else if(this.props.location.state && this.props.location.state.type == "share") {
shareType = 'facebook';
} else if (this.props.location.state && this.props.location.state.type == 'sharereply') {
shareType = 'sharereply';
}
return {
threadUserId: this.props.params.id,
activeShareType: shareType,
selectedThreads: selectedThreads
};
},
getStateFromFlux: function() {
var flux = this.getFlux();
var recordStoreState = flux.store('RecordStore').getState();
var threadStoreState = flux.store('ThreadStore').getState();
var appStoreState = flux.store('ApplicationStore').getState();
var reviewStoreState = flux.store('ReviewStore').getState();
var shareStoreState = flux.store('ShareStore').getState();
var demoState = flux.store('DemoStore').getState();
var activeRecord = recordStoreState.activeRecord || null;
var activeThread = threadStoreState.activeThread;
var activeRecordUser = null;
var authenticatedUser = appStoreState.demoMode? demoState.user : appStoreState.user;
var state = {
demoMode: appStoreState.demoMode,
playing: recordStoreState.playing,
recording: recordStoreState.recording,
activeThread: activeThread,
threads: threadStoreState.threads,
authenticatedUser: authenticatedUser,
activeRecord: activeRecord,
activeShareUser: shareStoreState.user,
shareId: shareStoreState.shareId
};
return state;
},
render: function() {
var threadClass = "thread";
var fbClass = "facebook";
var explanationText, usageContent;
var finishButtonClass = 'finish-button';
if(this.state.activeShareType == "thread") {
threadClass += ' active';
explanationText = i18n.t('content:review.reviewDoneExpl', {
count: this.state.selectedThreads.length,
context: this.state.selectedThreads.length == 0 ? 'doselect' : undefined
});
finishButtonClass += this.state.selectedThreads.length == 0 ? ' inactive' : '';
var threadCards = [];
var self = this;
_.each(this.state.threads, function(thread){
var threadUser = thread.user;
var threadUserPicture = threadUser.pictures[0].source;
var userName = threadUser.firstName + ' ' + threadUser.lastName;
var styleProps = {
backgroundImage : threadUserPicture ? 'url(' + threadUserPicture + ')': 'none'
};
var cls = "thread card" + (self.state.selectedThreads.indexOf(thread.id) != -1? " selected" : "");
threadCards.push(<div key={thread.id} className={cls} onClick={self.onThreadCardSelected} data-thread-id={thread.id}>
<div className='pic' style={styleProps}></div>
<div className='name'>{userName}</div>
<div className='checked micro-audio-icon-check'></div>
</div>);
});
//if thread cards array is null then we are displaying the required text
if(threadCards.length==0){
var text= "Du hast noch keine Freunde in audiyoh hinzugefugt (gehe dafur zur Suche).";
//displaying the content
usageContent = (
<div className="usage-target-container">
<p className="chat-text">{text} <br/>Uber <img className="share-icon" src={require('./../../../assets/images/share-active.png')} /> Teilen kannst du deine Aufnahme in aderen Kanale teilen.</p>
</div>);
//displaying the button
var finishContainer = <div className="finish-container">
<div className={finishButtonClass} >Fertige</div>
<div className="finish-text"><p className="chat-underbtn-text">Mindestens <b> ein Gesprach <br/> wahlen,</b> dem die Aufnahme <br/> hinzugefugt werden soll</p></div>
</div>;
}else{
usageContent = (
<div className="usage-target-container">
{threadCards}
</div>);
}
} else {
fbClass += ' active';
finishButtonClass += ' facebook';
explanationText = i18n.t('content:review.facebookExplanation');
//displaying the input box with the link and copy button
console.log("THe shareStoreState is " + this.state.shareId);
//the shareId is generate asynchroneously, so this.state.shareId can be null
if(typeof this.state.shareId === "string") {
//the link can be created like this:
var shareLink = window.location.origin + '/shared/' + this.state.shareId;
}
var usageContent = (
<div className="usage-target-container">
<div className="socialLinkContainer">
<p> Link zum Teilen </p>
<input className="copylink" type="text" value={shareLink} id="shareLink" /><br/>
<input className="copybtn" type="button" onClick={this.copytoclipboard} value="Link kopieren" />
</div>
</div>);
var finishContainer = <div className="finish-container">
<div className="social-media">
/*<img className="social-media-icon" src={require('./../../../assets/images/facebook.png')} />*/
<FacebookShareButton
url={shareLink}
quote={title}
className="social-media-icon">
<FacebookIcon
size={32}
round />
</FacebookShareButton>
<img className="social-media-icon" src={require('./../../../assets/images/whatsapp.png')} />
<img className="social-media-icon" src={require('./../../../assets/images/twitter.png')} />
<img className="social-media-icon" src={require('./../../../assets/images/instagram.png')} />
</div>
</div>;
}
var targetSwitchElements = [
<div title={i18n.t('content:review.sharethread')}
key="thread"
className={threadClass}
onClick={this.activateThreadShareType}><span>audiyoh-chat</span></div>,<br/>,
<div title={i18n.t('content:review.sharefb')}
key="facebook"
className={fbClass}
onClick={this.activateFBShareType}><span>Teilen</span></div>
];
//we either want to save a profile record a share response, so we dont need the fb/thread switch and thread cards
if(this.props.location.state && ["profile", "sharereply"].indexOf(this.props.location.state.type) != -1) {
var buttonText = i18n.t('content:review.profile');
if(this.props.location.state.type == "sharereply"){
buttonText = i18n.t('content:review.share', {name: this.state.activeShareUser.firstName});
}
targetSwitchElements = <div className="profile-record" onClick={this.onFinishRecord}>{buttonText}</div>;
usageContent = null;
finishContainer = null;
}
return (
<div className="ma-reviewing">
<div className="review-controls">
<div className="row">
<div className="col-3">
<a title={i18n.t('content:review.delete')} className="delete" onClick={this.deleteRecording}></a>
<a title={i18n.t('content:review.redo')} className="record" onClick={this.onRecordButtonClick}></a>
</div>
<div className="col-6">
<div className="review-container">
<ReviewOverlay
activeRecordUser={this.state.authenticatedUser}
record={this.state.activeRecord}
/>
</div>
</div>
{finishContainer}
<div className="col-3">
<div className="target-switch">
<p>Weiter mit der Aufnahme</p>
{targetSwitchElements}
</div>
</div>
</div>
</div>
<div className="upper" ref="upper">
<Menu location={this.props.location} />
<div className="menu">
</div>
</div>
<div className="upperguard" ref="upperguard"></div>
<div className="lower" ref="lower">
<div className="sizing-wrapper">
{usageContent}
</div>
</div>
</div>
);
},
deleteRecording: function(e) {
e.preventDefault();
if(this.props.location && this.props.location.state.userId) {
this.context.router.push({
pathname: "/thread/" + this.props.location.state.userId,
state: this.props.location.state
});
}
else {
this.context.router.push({
pathname: "/profile",
state: this.props.location.state
});
}
},
onRecordButtonClick: function(e) {
e.preventDefault();
this.context.router.push({
pathname: "/record",
state: this.props.location.state
});
},
onThreadCardSelected: function(syntheticEvent, reactId, e) {
var target = syntheticEvent.target.parentNode;
var threadId = target.getAttribute("data-thread-id");
var idx = this.state.selectedThreads.indexOf(threadId);
if(idx != -1) {
this.state.selectedThreads.splice(idx, 1);
this.setState({
selectedThreads: [].concat(this.state.selectedThreads)
});
}
else {
this.setState({
selectedThreads: [threadId].concat(this.state.selectedThreads)
});
}
},
activateThreadShareType: function() {
if(this.state.activeShareType == "thread") {
return;
}
this.setState({
activeShareType: 'thread'
});
},
activateFBShareType: function() {
if(this.state.activeShareType == "facebook") {
return;
}
this.setState({
activeShareType: 'facebook'
});
//this will store the record and generate a shareId
this.getFlux().actions.record.local.saveRecording({
type: "share"
});
/*var state1 = this.context.router.push({
pathname: '/review',
state: {
type: "profile",
role: "main"
}
});*/
//console.log("the state1 is " + state1);
//this.getFlux().actions.record.local.saveRecording(state1);
},
copytoclipboard: function(){
var copyText = document.getElementById("shareLink");
copyText.select();
document.execCommand("copy");
console.log("Copied the text: " + copyText.value);
},
onFinishRecord: function(e) {
if(e.target.classList.contains('inactive')) {
return;
}
if(this.props.location.state && ["profile", "sharereply"].indexOf(this.props.location.state.type) != -1) {
console.log(this.props.location.state);
this.getFlux().actions.record.local.saveRecording(this.props.location.state);
}
else if(this.state.activeShareType == "facebook") {
this.getFlux().actions.record.local.saveRecording({
type: "share"
});
}
else {
var data = {
type: "thread",
threadIds: this.state.selectedThreads
};
//we started recording from a thread, so we pass the userId to be able to return to this thread
//after saving
if(this.props.location.state && this.props.location.state.type == "thread") {
data.userId = this.props.location.state.userId;
}
this.getFlux().actions.record.local.saveRecording(data);
}
}
});
module.exports = Review;
I found my error!
The problem was that I initialized the require('react-share') in a variable reactShare and was using the component as
<FacebookShareButton url={shareLink} quote={title} className="social-media-icon">
<FacebookIcon size={32} round />
</FacebookShareButton>`
Instead, I should have initialized the require statement as
var FacebookShareButton = require('react-share');
Because of not declaring it properly React was yelling on me.
I hope this will save someones precious time. Cheers!

How can I make square-connect work with 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

How to do the Logic behind the next button in angularjs wizard

I have a customers.create.html partial bound to the WizardController.
Then I have 3 customers.create1,2,3.html partial files bound to WizardController1,2,3
Each WizardController1,2 or 3 has an isValid() function. This function determines wether the user can proceed to the next step.
The next button at the bottom of the pasted html should be disabed if ALL ? isValid() functions are false...
Thats my question but the same time that seems not correct to me.
I guess I am not doing the Wizard correctly...
Can someone please guide me how I should proceed with the architecture that the bottom next button is disabled when the current step isValid function returns false, please.
How can I make a connection from the WizardController to any of the WizardController1,2 or 3 ?
Is Firing an event like broadcast a good direction?
<div class="btn-group">
<button class="btn" ng-class="{'btn-primary':isCurrentStep(0)}" ng-click="setCurrentStep(0)">One</button>
<button class="btn" ng-class="{'btn-primary':isCurrentStep(1)}" ng-click="setCurrentStep(1)">Two</button>
<button class="btn" ng-class="{'btn-primary':isCurrentStep(2)}" ng-click="setCurrentStep(2)">Three</button>
</div>
<div ng-switch="getCurrentStep()" ng-animate="'slide'" class="slide-frame">
<div ng-switch-when="one">
<div ng-controller="WizardController1" ng-include src="'../views/customers.create1.html'"></div>
</div>
<div ng-switch-when="two">
<div ng-controller="WizardController2" ng-include src="'../views/customers.create2.html'"></div>
</div>
<div ng-switch-when="three">
<div ng-controller="WizardController3" ng-include src="'../views/customers.create3.html'"></div>
</div>
</div>
<a class="btn" ng-click="handlePrevious()" ng-show="!isFirstStep()">Back</a>
<a class="btn btn-primary" ng-disabled="" ng-click="handleNext(dismiss)">{{getNextLabel()}}</a>
'use strict';
angular.module('myApp').controller('WizardController', function($scope) {
$scope.steps = ['one', 'two', 'three'];
$scope.step = 0;
$scope.wizard = { tacos: 2 };
$scope.isFirstStep = function() {
return $scope.step === 0;
};
$scope.isLastStep = function() {
return $scope.step === ($scope.steps.length - 1);
};
$scope.isCurrentStep = function(step) {
return $scope.step === step;
};
$scope.setCurrentStep = function(step) {
$scope.step = step;
};
$scope.getCurrentStep = function() {
return $scope.steps[$scope.step];
};
$scope.getNextLabel = function() {
return ($scope.isLastStep()) ? 'Submit' : 'Next';
};
$scope.handlePrevious = function() {
$scope.step -= ($scope.isFirstStep()) ? 0 : 1;
};
$scope.handleNext = function(dismiss) {
if($scope.isLastStep()) {
dismiss();
} else {
$scope.step += 1;
}
};
});
durandalJS wizard sample code which could be used to rewrite a wizard for angularJS:
define(['durandal/activator', 'viewmodels/step1', 'viewmodels/step2', 'knockout', 'plugins/dialog', 'durandal/app', 'services/dataservice'],
function (activator, Step1, Step2, ko, dialog, app, service) {
var ctor = function (viewMode, schoolyearId) {
debugger;
if (viewMode === 'edit') {
service.editSchoolyear(schoolyearId);
}
else if (viewMode === 'create') {
service.createSchoolyear();
}
var self = this;
var steps = [new Step1(), new Step2()];
var step = ko.observable(0); // Start with first step
self.activeStep = activator.create();
var stepsLength = steps.length;
this.hasPrevious = ko.computed(function () {
return step() > 0;
});
self.caption = ko.observable();
this.activeStep(steps[step()]);
this.hasNext = ko.computed(function () {
if ((step() === stepsLength - 1) && self.activeStep().isValid()) {
// save
self.caption('save');
return true;
} else if ((step() < stepsLength - 1) && self.activeStep().isValid()) {
self.caption('next');
return true;
}
});
this.isLastStep = function() {
return step() === stepsLength - 1;
}
this.next = function() {
if (this.isLastStep()) {
$.when(service.createTimeTable())
.done(function () {
app.trigger('savedTimeTable', { isSuccess: true });
})
.fail(function () {
app.trigger('savedTimeTable', { isSuccess: false });
});
}
else if (step() < stepsLength) {
step(step() + 1);
self.activeStep(steps[step()]);
}
}
this.previous = function() {
if (step() > 0) {
step(step() - 1);
self.activeStep(steps[step()]);
}
}
}
return ctor;
});

how can i update the template view or json data so that i could re-render my template view in backbone.js

i want to update the view, as i click on follow button, id for follow button is btn-follow.
i want to update the ui if template, that i when i click on follow button, if value in console data is true follow button should change in "FOLLOW" if value in console is false then button caption should be UN-FOLLOW. how can i update the view or how can i update the joson data and re-render the template.
my view code is here.
spine.module("communityApp", function (communityApp, App, Backbone, Marionette, $, _) {
// Load template
var pforumTemplateHtml = App.renderTemplate("pforumTemplate", {}, "communityModule/tabContainer/pforum");
// Define view(s)
communityApp.Views.pforumView = Marionette.ItemView.extend({
template: Handlebars.compile($(pforumTemplateHtml).html()),
tagName: "li",
onRender: function () {
this.object = this.model.toJSON();
},
events: {
"click .btn-comment" : "showComments",
"click #recent-btn": "recent",
"click #my-posts": "myposts",
"click #popular-btn": "popular",
"click #follow-btn": "follow",
"click #my-posts": "LeftLinks",
"click #popular-btn": "LeftLinks",
"click .btn-follow": "activityBtn",
"click #like-btn" : "activityBtn",
"click #post-comments-btn": "showCommentEiditor"
},
postcomments : function ()
{
$("#recent-post-main-container").hide();
$("#recent-post-main-container2").show();
},
showCommentEiditor : function (){
$(".comment-popup-container").show();
$(".comment-txt-area").val('');
},
showPforumTab : function ()
{
$("#recent-post-main-container2").show();
$("#recent-post-main-container").hide();
},
showComments : function(){
$("#loading").show();
$(".tab-pane").hide();
$(".left-content").hide();
$("#recent-post-main-container2").show();
$(".left-content-commentEditor").show();
//$(".comm-tab-content-container").css('height','200px');
$(".comment-txt-area").val('');
$(".left-content-comment").show();
},
hideCommentPopup : function ()
{
$("#public-question-comment").hide();
},
// Show Loading sign
showLoading : function () {
$('#loading').show();
},
// UnLoading Function
hideLoading : function (){
$('#loading').hide();
},
// Add New Event Function
addEvent : function()
{
//$("#name").val(getBackResponse.user.FullName);
//$("#phone").val(getBackResponse.user.CellPhone);
//$("#email").val(getBackResponse.user.UserName);
$(".overly.addevent").show();
$('#lang').val(lat);
$('#long').val(long);
document.getElementById("my-gllpMap").style.width = "100%";
var my_gllpMap = document.getElementById("my-gllpMap");
google.maps.event.trigger( my_gllpMap, "resize" );
},
setValues : function(key,value)
{
window.localStorage.setItem(key,value);
},
getValues : function (key)
{
return window.localStorage.getItem(key);
},
closeAddEvent:function ()
{
$(".overly.addevent").hide();
},
// Show Over lay
showOverly:function ()
{
$('.overly-right-tab').show();
},
// Hide Loading sign
hideOverly : function()
{
$('.overly-right-tab').hide();
},
enlargeImage : function ()
{
$('#image').css('width','212px');
$('#image').css('height','150px');
},
activityBtn: function (e) {
var elem = $(e.target);
if (elem.hasClass('inactive')) {
return false;
}
var activity = elem.attr('name');
switch (activity) {
case "like-Button":
var _this = $.extend({},this,true);
_this.activity = 'like-Button';
this.activityBtnSubmit.call(_this);
break;
//
case "follow-button":
var _this = $.extend({},this,true);
_this.activity = 'follow-button';
this.activityBtnSubmit.call(_this);
break;
}
},
//For Like Post
activityBtnSubmit: function (modalThis) {
// var o = (this.parentThis) ? this.parentThis.object : this.object;
//var o = "52fa2ccc9bca9ac90c000051";
var func = _.bind(function () {
//var hmObj = new MessageApp.Controllers.hmAlertsController();
//hmObj.init();
}, this);
switch (this.activity) {
case "like-Button":
App.ids = null;
App.ids2 = null;
App.ids = this.object.id;
App.ids2 = this.object.iLiked;
if(App.ids2 === true) {
App.action = 0;
}
else if(App.ids2 === false) {
App.action = 1;
}
var data = {
id: this.object.id,
iLiked:App.action,
sessionToken:loginUser.sessionToken,
};
$.when(App.request('alertActivity:entities', {
origin: 'pforum',
id: this.object.id,
iLiked:(App.action),
sessionToken:loginUser.sessionToken,
//value : value,
dataToSend: JSON.stringify(data),
activity:this.activity,
}))
.then(func);
App.ids1 = (data.id);
break;
case "follow-button":
App.ids = null;
App.ids2 = null;
App.ids = this.object.UserId;
App.ids2 = this.object.iFollow;
if(App.ids2 === true) {
// $(".btn-follow").html("UN-FOLLOW");
App.action = 0;
}
else if(App.ids2 === false) {
//$(".btn-follow").html("FOLLOW");
App.action = 1;
}
if (App.ids) {
alert (App.ids);
$(".btn-follow").html("UN-FOLLOW");
//App.action = 0;
}
else
{
$(".btn-follow").html("FOLLOW");
//App.action = 1;
}
var data = {
id: this.object.UserId,
iFollow:App.action,
sessionToken:loginUser.sessionToken,
};
$.when(App.request('alertActivity:entities', {
origin: 'pforum',
id: this.object.UserId,
iFollow:(App.action),
sessionToken:loginUser.sessionToken,
//value : value,
dataToSend: JSON.stringify(data),
activity:this.activity,
}))
.then(func);
App.ids1 = (data.UserId);
break;
}
return true;
}
});
var RowView = Backbone.View.extend({
events: {
"click .btn-follow": function() {console.log(this.model.get("name"));}
},
initialize: function(){
this.model.on('change', this.render, this);
},
render: function() {
var html=_.template(rowTemplate,this.model.toJSON());
this.setElement( $(html) );
return this;
},
});
// define collection views to hold many communityAppView:
communityApp.CollectionViews.pforumCollectionViews = Marionette.CollectionView.extend({
tagName: "ul",
itemView: communityApp.Views.pforumView
});
});
my template code is here.
<div>
<div class="comm-tab-row">
<div class="post-left-panel">
<div class="post-image-container">
<img src="{{UserImageURL}}" alt="" class="post-image" /></br>
{{#if iLiked}}
<img src="images/myCommunity/liked#2x.png" width="20" height="19" id="like-btn" name = "like-Button" >
{{else}}
<img src="images/myCommunity/like#2x.png" width="20" height="19" id="like-btn" name = "like-Button" >
{{/if}}
({{NumLikes}})
</div>
</div>
<div class="post-body">
<h5 class="comm-tab-heading">
<span class="navigate-screen" id="{{Id}}" style="text-decoration:underline;">
{{UserName}}
</span>
<span>
-
</span>
<span>
{{format_date Time ""}}
</span>
</h5>
{{Message}}
</div>
<div class="comm-right-panel">
{{#if iFollow}}
UN-FOLLOW
{{else}}
FOLLOW
{{/if}}
{{NumComments}} - COMMENT
</div>
</div>
You can add a new boolean to the model of your view isFollowing. You can then add a condition inside your template to determine which button to render.
<% if(isFollowing){ %>
<button> Unfollow </button>
<% } else { %>
<button> Follow</button>
<% } %>
To rerender the view call the render function from your event handler.
events: {
"click .btn-follow": function() {
//Do comething useful..
this.render();
}
},

ngClick not firing when $swipe is bound

I have an ngClick directive on elements that are also bound to $swipe. The ngClick doesn't fire (it was firing before the $swipe was added).
I'm using jQuery mobile combined with AngularJS.
Interestingly, my diagnostics show a swipe event with start and end the same - seems to contradict the minimum swipe distance, but perhaps the cancel function is being called. Possibly I could use the cancel function to find out where the click occurred but I feel I shouldn't have to do that.
The site is viewable at http://skimobile.cbdweb.net
HTML
<div id="matrix" data-role="page" ng-controller="matrixCtrl" ng-init="init()">
<div data-role="header">
<?php echo CHtml::encode($this->configs['SITENAME']); ?> Bookings
</div>
<div data-role="content">
<div class="lodgename noborder"> </div>
<div class="oneday onemonth" ng-repeat="m in months" ng-style="callMonthstyle(m)" ng-class="$last ? 'lastcol' : ''" on-finish-days>
{{monthNames[m.month]}} {{m.year}}
</div>
<br clear="both" />
<div class="lodgename noborder"> </div>
<div class="oneday" ng-style="callDaystyle()" ng-class="$last ? 'lastcol' : ''" ng-repeat="d in dates">
{{d.getDate()}}
</div>
<br clear="both" />
<div ng-repeat="lodge in data.lodges">
<div class="lodgename" ng-class="$last ? 'lastrow' : ''">{{lodge.lodgetitle}}</div>
<div class="oneday" ng-style="callDaystyle()" ng-class="($last ? 'lastcol' : '') + ' ' + ($parent.$last ? 'lastrow' : '')" ng-repeat="d in dates" ng-click="showDate(lodge, d)">
</div>
<br clear="both" />
</div>
<div ng-show="data.debug" style="margin-top: 20px;"
<ul>
<li>
move = {{swipe.move}}
</li>
<li>
start = {{swipe.start}}
</li>
<li>
end = {{swipe.end}}
</li>
<li>
scope.startDay = {{startDay}}
</li>
<li>
daysMoved = {{swipe.daysMoved}}
</li>
<li>
daysFinished = {{nDaysFinished}}
</li>
</ul>
</div>
<ul>
<?php foreach(Yii::app()->params['lodges'] as $lodgecode=>$lodge) {
echo "<li>" . $lodgecode . " = " . $lodge['lodgetitle'] . "</li>";
$lci = $this->lodgeconfigs[$lodgecode]['PREFIX_BOOKING_ID'];
echo "<LI>" . $lci . "</li>";
} ?>
</ul>
</div>
</div>
Javascript:
/* NG services */
var matrix = angular.module('Skimobile', ['ngTouch']);
matrix.factory('dayswidth', ['writeDays', function(){ // gets called on window change width
return function(scope, ww) {
var lodgename = $('.lodgename').first().width() + 4; // 4 = padding in lodgename class
var padding = 60 + lodgename;
var oldDisplayDays = scope.displayDays;
scope.displayDays = Math.min(28, (ww - padding)/scope.mindaywidth); // show at most 28 days, fewer if needed to maintain minimum width
scope.dayWidth = Math.floor( (ww-padding) / scope.displayDays );
if(oldDisplayDays!=scope.displayDays) { // avoid changing scope.dates as this will cause infinite recursion in the $digest on ng-repeat d in dates
scope.callWriteDays();
}
};
}]);
matrix.factory('writeDays', function() {
return function(scope) {
var d = new Date();
d.setTime(scope.startDay.getTime());
scope.dates = []; // repeat on this to draw days
scope.months = []; // repeat on this to draw months
var yearShown = false; // only show year once, when the month is long enough
var m = d.getMonth();
var daysLeft = 0; // days shown belonging to each month
for(i=0; i<scope.displayDays; i++) {
scope.dates.push(new Date(d.getTime()));
var oldd = new Date(d.getTime());
d.setDate(d.getDate()+1);
daysLeft++;
var newm = d.getMonth();
if(newm!=m) { // finished a month, display it
var newMonthObj = {month:m, days:daysLeft};
if(!yearShown && daysLeft*scope.dayWidth-1-4>3*scope.mindaywidth) {
newMonthObj.year = oldd.getFullYear();
yearShown = true;
} else {
newMonthObj.year = '';
}
scope.months.push(newMonthObj);
m = newm;
daysLeft = 0;
}
}
if(daysLeft>0) { // final month
newMonthObj = {month:m, days:daysLeft};
newMonthObj.year = yearShown ? '' : oldd.getFullYear();
scope.months.push(newMonthObj);
}
}
});
matrix.factory('daystyle', function(){
return function(scope) {
return {
'width': (scope.dayWidth-1) + 'px'
}; // -1 allows for border
}
});
matrix.factory('monthstyle', function(){
return function(scope, m) {
var days = m.days;
return {
'width': (scope.dayWidth*days-1-4) + 'px'
} // 1 for border, 4 for padding-left
}
});
matrix.directive('onFinishDays', function($timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
if(scope.$last === true) { // without this it gets called once per visible month!
$timeout(function() {
scope.$emit('daysFinished');
})
}
}
}
});
/* NG controllers */
function matrixCtrl($scope, dayswidth, writeDays, daystyle, monthstyle, $swipe) {
$scope.callDayswidth = function(w){
dayswidth($scope, w);
};
$scope.callDaystyle = function() {
return daystyle($scope);
}
$scope.callMonthstyle = function(m) {
return monthstyle($scope, m);
}
$scope.callWriteDays = function() {
return writeDays($scope);
}
$scope.data = _main; // passed via Yii layout file
$scope.mindaywidth = 30;
$scope.monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var d = new Date(); // initially the matrix starts from today
$scope.startDay = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
var w = $(window);
$scope.getWindowDimensions = function() {
return {'h': w.height(), 'w': w.width()};
};
$scope.$watch($scope.getWindowDimensions, function(newValue, oldValue){
$scope.callDayswidth(newValue.w);
}, true);
w.bind('resize', function() {
$scope.$apply();
})
$scope.showDate = function(lodge, d){
alert(lodge.lodgetitle + ' ' + d.getDate());
}
$scope.swipe = {};
$scope.nDaysFinished = 0;
$scope.$on('daysFinished', function(event) {
$scope.nDaysFinished++;
$swipe.bind($('.oneday'), {
end:function(loc){
$scope.swipe.end = loc.x;
$scope.swipe.daysMoved = Math.floor((loc.x - $scope.swipe.start) / $scope.dayWidth);
$scope.startDay.setTime($scope.startDay.getTime() - $scope.swipe.daysMoved*24*60*60*1000); // compute new start day at end of drag;
$scope.callWriteDays();
$scope.$apply();
}
})
});
}

Resources