Duplicated Paypal buttons with Paypal REST API and AngularJS - angularjs

I'm building an Single Page App where the paypal button is generated on ng-click from a button (Add products).
The problem I'm facing, is that if the user clicks this button several times, the app will generate several buttons one after the other.
This can very well happen as the user might click the button, but then go back and add an extra product, before finish the purchase.
How could I manage to remove all existing buttons before adding the new one?
The function looks like this:
$scope.formulari = function(){
paypal.Button.render({
env: 'production', // Or 'sandbox'
locale: 'es_ES',
style: {
label: 'paypal',
...
And after a few clicks, my initial HTML button <a id="paypal-button"></a> looks like this:
<a id="paypal-button">
<div id="xcomponent-paypal-button-6d3dcbc0c4" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
<div id="xcomponent-paypal-button-46823018c3" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
<div id="xcomponent-paypal-button-41aad29e14" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
<div id="xcomponent-paypal-button-48d3247535" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
</a>

Generating a button on click might not be the way you want to go with an AngularJs structure. Editing your DOM structure is more a jQuery thing and in general you don't want to mix the two (Some explanations of why: 1, 2).
An Angular way to pick this up would be the following (Explanation beneath snippet):
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.articles = ['PC', 'Playstation', 'Xbox'];
$scope.cart = [];
$scope.addArticleToCart = function(article) {
$scope.cart.push(article);
}
$scope.clearCart = function() {
$scope.cart = [];
}
$scope.doPaypalThings = function() {
//REST API stuff
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="article in articles">
<button ng-click="addArticleToCart(article)">
{{article}}
</button>
</div>
<br>
<div ng-show="cart.length > 0">
<button id="paypal-button" ng-click="doPaypalThings()">
Paypal
</button>
</div>
<br>
<div>
In cart:
</div>
<div ng-repeat="item in cart">
{{item}}
</div>
<br>
<div>
<button ng-click="clearCart()">
Clear cart
</button>
</div>
</div>
</body>
</html>
With this method the button always exists, it just isn't visible until the requirements within the ng-show are met. In the example, the requirement is that there are items in the cart. You will notice that once the requirements are no longer met the button will disappear again.
An opposite of ng-show is ng-hide which can be used in the same way:
ng-hide="cart.length == 0" or ng-hide="cart.length < 1
If you're dead set on using your current method, you can check out this answer here, although it is not Angular.

Related

Donot want the array to display simultaneously in angularjs

I have created an array example. There is a text box that accepts the number and on clicking on add, it adds the number to a defined array. And on display i want it to display the array. But what is happening is, as soon as i click on add button, the number simultaneously is being displayed on the HTML page. I guess its because of ng-model, but i want it to be displayed only when i click on display button. Please help.
<html ng-app="Swabhav.Array">
<head>
<title>Array</title>
<script src="angular.js"></script>
</head>
<body>
<div ng-controller="ArrayController">
<input type="text" ng-model="arraynumber">
<button type="button" value="Add" ng-
click="addElementToArray(arraynumber)">Add</button>
<button type="button" value="Display" ng-
click="displayElementsInArray()">Display</button>
<li ng-repeat="element in elements track by $index ">
<h4> {{element}} </h4>
</li>
</div>
<script>
angular.module("Swabhav.Array",[])
.controller("ArrayController",
["$scope","$log",function($scope,$log){
$scope.numbers=[];
$scope.number="";
$scope.addElementToArray=function(number){
$scope.numbers.push(number);
$log.log("inside add "+ $scope.numbers)
}
$scope.elements=[];
$scope.displayElementsInArray=function(){
$log.log("Inside Display")
$scope.elements.push($scope.numbers);
}
}])
</script>
</body>
</html>
You can try like the below code, also check this working plunker link for your example scenario.
Controller:
$scope.numbers=[];
$scope.elements=[];
$scope.addElementToArray=function(number){
$scope.numbers.push(number);
$scope.arraynumber='';
};
$scope.displayElementsInArray=function(){
angular.extend($scope.elements, $scope.numbers)
};

Angular JS translate not working properly inside Visualforce page

I need to translate my HTML into different languages based on user preference. For that, I am using Angular JS translate method. The example when I write inside notepad and saved as ".html" is working fine. But when I pasted the same code inside my Salesforce Visualforce page, its behavior changes.ie. When I click on the button"IT" to translate the content to "Italics" the contents are translating to Italics but within seconds the contents are again going back to their preferred language "EN". I have given below my screenshot of output.
I have given below my code, can anyone say what's wrong in this.
<!DOCTYPE html>
<html ng-app="app">
<head>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://cdn.rawgit.com/angular-translate/bower-angular-translate/2.5.2/angular-translate.js"></script>
<script>
// Code goes here
var app = angular.module('app', ['pascalprecht.translate']);
app.config(['$translateProvider',
function($translateProvider) {
$translateProvider.translations('it', {
'Purchase order': "Ordine di acquisto ",
'Number:': "Numero:",
'Customer data': "Dati Cliente",
'Surname / Company':"Cognome/Società",
'Name':"Nome",
'Piazza way':"Via/Piazza",
'City':"Città",
'VAT tax code':"Codice Fiscale/Partita IVA",
'Phone':"Telefono",
'E-Mail':"E-Mail",
'CAP':"CAP"
});
$translateProvider.preferredLanguage("en");
}
]);
app.controller('AppController', function ($translate) {
// this.browser = navigator.userAgent;
this.useLang = function (lang) {
$translate.use(lang);
}
});
</script>
<div ng-controller="AppController as app">
<h3 translate> Purchase order </h3>
<p translate>Number:</p>
<h3 translate>Customer data</h3>
<p><span translate>Surname / Company</span>_________</p>
<p> <span translate>Name</span>__________</p>
<p><span translate>Piazza way</span>____________</p>
<p><span translate>CAP</span>_______<span translate>City</span>______</p>
<p><span translate>VAT tax code</span>__________</p>
<p><span translate>Phone</span>____________</p>
<p><span translate>E-Mail</span>_________</p>
<button ng-click="app.useLang('it')">IT</button>
<button ng-click="app.useLang('en')">EN</button>
</div>
</body>
</html>
try this
{{'variable_name' | translate }}
After going through the solutions provided in developer forums, finally I found the solution for my problem. Actually the reason behind my content going back to "english" from "italics" is "page refreshing". To stop the page from refreshing I need to set the <button> type as "button".
ie <button type="button">
Code change
<button type="button" ng-click="app.useLang('it')">IT</button>
<button type="button" ng-click="app.useLang('en')">EN</button>
I did the change in my code and it stopped the page from refreshing, which in turn gave my expected result.

use ngStorage values in the template of site

I've got a site that uses ngStorage to save cart data until checkout, when it is then stored in the database. When using vm.$storage = $localStorage; in my controller, I can access the cart information easily for the part of the page in the section of index.html but I WANT to be able to access and display information from ngStorage in the header of my site, which is nested inside .
I've tried adding ng-controller="SiteController" to my li tag but still don't get anything to display that way.
How can I get the localStorage using ngStorage to display in the template (index.html) of my site?
My index.html file is setup something like this:
<html ng-app="myApp">
<body>
// a bunch of code to show my other navigation
// code to show my shopping cart at a glance
<li class="quick-cart">
<a href="#">
<span class="badge badge-aqua btn-xs badge-corner">
{{vm.$storage.cart.items.length}}
</span>
<i class="fa fa-shopping-cart"></i>
</a>
<div class="quick-cart-box">
<h4>Shop Cart</h4>
<div class="quick-cart-wrapper">
<a href="#"><!-- cart item -->
<h6>Item Name</h6>
<small>$12.34</small>
</a><!-- /cart item -->
<!-- cart no items example -->
<!--<a class="text-center" href="#"><h6>0 ITEMS ON YOUR CART</h6></a>-->
</div>
<!-- quick cart footer -->
<div class="quick-cart-footer clearfix">
VIEW CART
<span class="pull-left"><strong>TOTAL:</strong> $54.39</span>
</div>
<!-- /quick cart footer -->
</div>
</li>
//other code between the header and controller content
<div ng-view></div> //the CONTENT section controlled by each controller
//other code to finish the page
My site-controller.js code is:
/* global angular */ angular.module('myApp')
.controller('SiteController', SiteController);
function SiteController($route, $routeParams, AuthFactory, jwtHelper, $window, $localStorage, $sessionStorage) {
var vm = this;
vm.$storage = $localStorage;
vm.$storage.cart = vm.$storage.cart;
console.log(vm.$storage.cart);
}
Since you are using controllerAs syntax in controller you need to use the as alias in ng-controller
ng-controller="SiteController as vm"
This defines the vm you are already using in the view for:
{{vm.$storage.cart.items.length}}

AngularJS ng-show 2 way binding not working

I am new to AngularJS and I have seen others asking similar questions, but the answers are not working for me. Rather than hijacking those questions, I thought I would open one for myself.
I am creating a demo app -- it lists "sites" which can be added to or deleted. I am using the ng-show attribute to display the required html div while hiding the others.
Here is the back-end javascript--
var SiteMaintenanceModule = angular.module("SitesMaintenance", []);
SiteMaintenanceModule.controller("siteCtrl", diveSiteCtrlfn);
function diveSiteCtrlfn($scope) {
// initializing the sites array
$scope.sites = sites;
//initializing the Divs array
$scope.allowedDivs = ["listSiteDiv","addSiteDiv", "editSiteDiv","deleteSiteDiv"];
// setting the first div as selected. This should show the div which lists the sites
$scope.selectedDiv = $scope.allowedDivs[0];
// function to be called with the selected div is to be changed
$scope.setSelectedDiv = function ($divSelectedByUser) {
$scope.selectedDiv = $divSelectedByUser;
}
};
And here is the html
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="SitesMaintenance">
<head>
<title>List of Dive Sites</title>
<link rel="Stylesheet" href="./../zHelpers/bootstrap/css/bootstrap.css" />
<script src="./../zHelpers/angular.min.js"></script>
<script src="./sites.js"></script>
<script src="./SiteMaintenance.js"></script>
</head>
<body ng-controller="siteCtrl">
<!-- Display the list of sites based on the selectedDiv variable-->
<div id="SiteList" ng-show="{{selectedDiv == 'listSiteDiv'}}">
<h3>List of Sites</h3>
<ul ng-repeat="site in sites" ng-model="sites">
<li>{{site.site}} in {{site.location}}</li>
</ul>
</div>
<!-- Display the add site Div based on the selectedDiv variable-->
<div id="AddSite" ng-show="{{selectedDiv == 'addSiteDiv'}}">
<h3>Add New Site</h3>
<div style="display:block; margin:10px">Site: <input id="inputAddSiteName" /></div>
<div style="display:block; margin:10px">Location: <input id="inputAddSiteLocation" /></div>
</div>
<!-- Display the edit site Div based on the selectedDiv variable -->
<div id="EditSites" ng-show="{{selectedDiv == 'editSiteDiv'}}" style="display:block;margin:20px">
Site Name:<input id="InputEditSiteName" />
Site Location:<input id="InputEditSiteLocation" />
</div>
<div id="controls">
<button id="AddNewSiteButton" ng-click="setSelectedDiv('addSiteDiv')">Add Site</button>
<button id="DeleteSiteButton" ng-click="setSelectedDiv('deleteSiteDiv')">Delete Site</button>
<button id="EditSiteButton" ng-click="setSelectedDiv('editSiteDiv')">Edit Site</button>
</div>
</body>
I can set the visible div to whatever I want at the start, by changing the index in the statement "$scope.selectedDiv = $scope.allowedDivs[0];" in the JavaScript.
I change the value of $scope.selectedDiv when any of the buttons on the page are clicked, so as to change the visibility of the divs.
However, the visibility of the divs doesn't change, no matter what the value of $scope.selectedDiv is. In fact, when debugging in chrome, I see that the attribute value of ng-show for each of my divs updates dynamically to "true" or "false" and expected, but the div is still displayed -- the initially invisible divs seems to have a class="ng-hide" attribute, which never changes.
I have tried $scope.$apply() in the JavaScript but that gives errors. Any help would be greatly appreciated.
You don't need to use {{}} interpolation inside ng-show directive directive, it evaluates the expression inside a $scope of your controller directly.
ng-show="selectedDiv == 'addSiteDiv'"
ng-show="selectedDiv == 'listSiteDiv'"
ng-show="selectedDiv == 'editSiteDiv'"

Live search in AngularJS: updating the results

I want a live search: the results are queried from web api and updated as the user types.
The problem is that the list flickers and the "No results" text appears for a fraction of second, even if the list of results stays the same. I guess I need to remove and add items with special code to avoid this, calculating differences between arrays, etc.
Is there a simpler way to avoid this flicker at least, and probably to have possibility to animate the changes?
It looks like this now:
The html part is:
<div class="list-group">
<a ng-repeat="test in tests track by test.id | orderBy: '-id'" ng-href="#/test/{{test.id}}" class="list-group-item">
<h4 class="list-group-item-heading">{{test.name}}</h4>
{{test.description}}
</a>
</div>
<div ng-show="!tests.length" class="panel panel-danger">
<div class="panel-body">
No tests found.
</div>
<div class="panel-footer">Try a different search or clear the text to view new tests.</div>
</div>
And the controller:
testerControllers.controller('TestSearchListCtrl', ['$scope', 'TestSearch',
function($scope, TestSearch) {
$scope.tests = TestSearch.query();
$scope.$watch('search', function() {
$scope.tests = TestSearch.query({'q':$scope.search});
});
}]);
You should use ng-animate module to get the classes you need for smooth animation. For each ng-repeat item that's moved, added, or removed - angular will add specific classes. Then you can style those classes via CSS or JS so they don’t flicker.
An alternative way of doing what you require is to use the angular-ui bootstrap Typeahead component (check at the bottom of the post). It has a type-ahead-wait property in milliseconds and also a template url for customising it.
<div ng-app>
<div ng-controller="MyController">
<input type="search" ng-model="search" placeholder="Search...">
<button ng-click="fun()">search</button>
<ul>
<li ng-repeat="name in names">{{ name }}</li>
</ul>
<p>Tips: Try searching for <code>ann</code> or <code>lol</code>
</p>
</div>
</div>
function MyController($scope, $filter) {
$scope.names = [
'Lolita Dipietro',
'Annice Guernsey',
'Gerri Rall',
'Ginette Pinales',
'Lon Rondon',
'Jennine Marcos',
'Roxann Hooser',
'Brendon Loth',
'Ilda Bogdan',
'Jani Fan',
'Grace Soller',
'Everette Costantino',
'Andy Hume',
'Omar Davie',
'Jerrica Hillery',
'Charline Cogar',
'Melda Diorio',
'Rita Abbott',
'Setsuko Minger',
'Aretha Paige'];
$scope.fun = function () {
console.log($scope.search);
$scope.names = $filter('filter')($scope.names, $scope.search);
};
}

Resources