View variable does not get injected in the $scope - angularjs

The view:
<div class="numbers">
{{calc.amount || 0 }}
</div>
<div class="keypad">
<div class="number-slot"><button ng-click="numberPressed(1)" class="number">1</button></div>
</div>
The controller:
app.controller('pay-amount', function ($scope, $state, $cordovaBarcodeScanner, ionicMaterialInk) {
$scope.numberPressed = function (number) {
console.log(number + " pressed!");
$scope.calc = {
amount: "" + $scope.calc.amount + number
}
};
ionicMaterialInk.displayEffect();
});
There are no errors till numberPressed(1) is called:
"ionic.bundle.js:26794 TypeError: Cannot read property 'amount' of
undefined".
Upon inspecting $scope, I can't find the "calc" object I defined in the view. What am I missing here?

You need to declare the $scope variable before using it,
$scope.calc = {amount:0};
DEMO

Try this,
$scope.numberPressed = function (number) {
console.log(number + " pressed!");
$scope.calc = {amount:''};
$scope.calc = {
amount: "" + $scope.calc.amount + number
}
console.log($scope.calc);
};

Your calc was never set on the $scope so it tries to find amount on undefined
You could make 2 simple changes
$scope.calc = {};
$scope.numberPressed = function (number) {
console.log(number + " pressed!");
$scope.calc.amount = ($scope.calc.amount || 0) + number
}
or
$scope.calc = { amount: 0 };
$scope.numberPressed = function (number) {
console.log(number + " pressed!");
$scope.calc.amount = $scope.calc.amount + number
}

Try this,
$scope.calc = { amount: 0 };
$scope.numberPressed = function (number) {
console.log(number + " pressed!");
$scope.calc.amount = $scope.calc.amount + number
}

Related

passing variable value from controller to view in AngularJS

I am developing an application where i popup a window and when it gets popup the next time i will try to open it should not be opened. Next time it should open When i will close the popup then it should open.
Now for that i am using count variable and whenever it will be 1 the popup opens and whenever it is greater than or equal to 2 it shows alert. But now when i close the popup it is not resetting the value of count to 0 in view.
In JSfiddle i tried using var self = this; it works fine but when i tried it on my code it says Uncaught Exception Typeerror cannot find property 'count' defined at line self.count = 0;
How to achieve this? or any alternate solution for this?
<a ui-sref-active="active" ng-click="count=count+1; connectMachine(machine, count)" ng-init="count=0" ><span><i class="fa fa-desktop fa-5x"></i></span></a>
$scope.connectMachine = function(machine, count) {
var promise = restAPIService.connectMachineService(
$scope.thisStudentThisBatch.guacProfileId,
machine.connectionId, $stateParams.batchID).get();
promise.$promise.then(function(response) {
var json = JSON.parse(response.data);
console.log(json.id);
var dnsUrl = $location.absUrl().split('/');
dnsUrl = dnsUrl[0] + '//' + dnsUrl[2];
var apiUrl = dnsUrl + $rootScope.apiUrl + "guacamole/disconnect/"
+ json.id;
var conn_params = $http.defaults.headers.common.Authorization
+ "++" + apiUrl;
$scope.machineURL = response.headers.url + "&conn_params="
+ conn_params;
var params = "height=" + screen.availHeight + ",width="
+ screen.availWidth;
var NewWin;
var self = this;
if ($scope.count == 1) {
NewWin = window.open($scope.machineURL);
} else if ($scope.count >= 2) {
alert("Back Off Back Off");
}
function checkWindow() {
if (NewWin && NewWin.closed) {
window.clearInterval(intervalID);
self.count = 0;
}
}
var intervalID = window.setInterval(checkWindow, 500);
}, function(error) {
dialogs.error("Error", error.data.error, {
'size' : 'sm'
});
});
}
You can use a variable defined on $scope to trigger the value of button instead of using ng-init
HTML:
<div ng-app="myApp">
<ul ng-controller="TodoCtrl">
<li class="list-group-item" ng-repeat="todo in todos">{{todo.text}}
<button class="btn btn-default" ng-click="addLike($index)">value- {{count[$index]}}</button>
</li>
</ul>
</div>
JS:
var myApp = angular.module('myApp', []);
function TodoCtrl($scope) {
$scope.todos = [{
text: 'todo one'
}, {
text: 'todo two',
done: false
}];
$scope.count = [0, 0];
$scope.addLike = function(index) {
var NewWin;
$scope.count[index] ++;
if ($scope.count[index] == 1) {
NewWin = window.open('https://www.google.com');
} else if ($scope.count >= 2) {
alert("Back Off Back Off");
}
function checkWindow() {
if (NewWin && NewWin.closed) {
window.clearInterval(intervalID);
$scope.count[index] = 0;
$scope.$apply();
}
}
var intervalID = window.setInterval(checkWindow, 500);
};
};
JS Fiddle :https://jsfiddle.net/p41dLjmn/

Angular filter to initialise first name

I need to make an angular filter that will take full names, and initialise the first name, leaving only the last name, except in certain cases (e.g. Van Aanholt).
So the following:
Yohan Cabaye
Oscar
Jordi Alba Ramos
Patrick Van Aanholt
Hatem Ben Arfa
Will be shown as:
Y. Cabaye
Oscar
J. Ramos
P. Van Aanholt
H. Ben Arfa
Any help would be appreciated.
UPDATE: This is what I've tried...
angular.module('euroFilters', [])
.filter('initialiseName', function() {
return function(name) {
var nameArr = name.split(' ');
var firstName = nameArr[0];
var firstNameInitial = nameArr[0][0] + ". ";
var lastName = nameArr[nameArr.length - 1];
var secondaryLastName = nameArr[nameArr.length - 2];
// If only one name (standard)...
if (nameArr.length <= 1) {
return firstName;
}
// If more than one name, and contains "Van" or "Ben" (exception)...
else if (secondaryLastName === "Van" || secondaryLastName === "Ben") {
return firstNameInitial + " " + secondaryLastName + " " + lastName;
}
// If more than one name (standard)...
else if (nameArr.length > 1) {
return firstNameInitial + lastName;
}
};
});
Is there a more elegant way to write this? How would it convert into a switch statement, for example?
You can use split and join for that. String are array like objects, so you can use index on them.
angular.module('app', []);
angular.module('app').filter('initialiseFirstName', function () {
return function (name) {
var parts = name.split(/\s+/);
if (parts.length <= 1) {
return name;
}
var first = parts[0][0] + '.';
return first + ' ' + parts.slice(1).join(' ');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
{{'John Ket'|initialiseFirstName}}
</div>
This should do what you need:
<div ng-app="app">
{{'John Von Koten'|initialiseFirstName}}
</div>
<script>
angular.module('app', []);
angular.module('app').filter('initialiseFirstName', function () {
function checkName(name){
var prefixes = ['Van', 'Ben', 'Von'];
for(var i = 0; i < prefixes.length; i++){
if(name.indexOf(prefixes[i]) > 0){
return true;
}
}
return false;
}
return function (name) {
var parts = name.split(/\s+/);
if (parts.length <= 1) {
return name;
}
if(parts.length > 2){
if(checkName(name)){
return parts[0][0] + '. ' + parts[1] + ' '+ parts[2];
}
}
var first = parts[0][0] + '.';
return first + ' ' + parts.slice(1).join(' ');
}
});
</script>

Is this a correct way of pagination in angularjs?

On clicking "more" i call loadNextPage method that call loadComments method which load data based next id nextCommentId and push the data to allComments array and this array is rendered in html
$scope.loadNextPage = function()
{
loadComments($scope.nextCommentId);
}
function loadComments(page){
$scope.allComments.push(d.data);
..
..
$scope.nextCommentId = nextId;
}
Here is my html
<div ng-repeat="comment in allComments">
...
</div>
My question is, is this the correct way of doing pagination in angularjs as i am keeping all data in array so if data will grow it will consume memory.
<div data-pagination="" data-num-pages="numPages()"
data-current-page="currentPage" data-max-size="maxSize"
data-boundary-links="true"></div>
todos.controller("TodoController", function($scope) {
$scope.filteredTodos = []
,$scope.currentPage = 1
,$scope.numPerPage = 10
,$scope.maxSize = 5;
$scope.makeTodos = function() {
$scope.todos = [];
for (i=1;i<=1000;i++) {
$scope.todos.push({ text:"todo "+i, done:false});
}
};
$scope.makeTodos();
$scope.numPages = function () {
return Math.ceil($scope.todos.length / $scope.numPerPage);
};
$scope.$watch("currentPage + numPerPage", function() {
var begin = (($scope.currentPage - 1) * $scope.numPerPage)
, end = begin + $scope.numPerPage;
$scope.filteredTodos = $scope.todos.slice(begin, end);
});
});

Grouping variable number of elements with React / JSX

I have a situation where I have a variable number of objects in an array, and I need to create groups of three. I know that to iterate over an array I can do something like this (Fiddle - https://jsfiddle.net/o5pbttjq/):
render: function() {
var random = Array.apply(null, Array((Math.floor(Math.random() * (15 - 1) + 1) + 1))).map(Number.prototype.valueOf,0).map(function(d,i) {return i});
return (
<div>
{random.map(function(d) {
return <p>{d}</p>
})}
</div>
);
}
I can also group them like so, but it's quite ugly (Fiddle - https://jsfiddle.net/Lxqm3tzo/):
render: function() {
var random = Array.apply(null, Array((Math.floor(Math.random() * (15 - 1) + 1) + 1))).map(Number.prototype.valueOf,0).map(function(d,i) {return i});
var content = "<div>";
random.forEach(function(d, i) {
if (i % 3 === 0 && i !== 0) {
content += "</div><div>"
}
content += "<p>" + d + "</p>"
})
content += "</div>"
return (
<div dangerouslySetInnerHTML={{__html: content}}></div>
);
}
How can I create groups of a variable number of objects with JSX?
The following will work without having to set the innerHTML. See the fiddle here: https://jsfiddle.net/kuvvd513/8/
var Hello = React.createClass({
render: function() {
var random = Array.apply(null, Array((Math.floor(Math.random() * (15 - 1) + 1) + 1))).map(Number.prototype.valueOf,0).map(function(d,i) {return i});
var allGroups = [];
var group = [];
random.forEach(function(d, i) {
if (i % 3 === 0 && i !== 0) {
allGroups.push(<div> {group} </div>);
group = [];
}
group.push(<p> {d} </p>);
}.bind(this));
allGroups.push(<div> {group} </div>);
return (
<div>
{allGroups}
</div>
);
}
});
React.render(<Hello name="World" />, document.getElementById('container'));

Angularjs Directive with ngModel

I've got a javascript function that we use in a legacy system that alters the format of an input field as you type;
function checkValidDate(dateStr) {
if (dateStr && dateStr != '') {
dateStr = dateStr.replace('/', '');
dateStr = dateStr.replace('/', '');
var d_f_m = dateStr;
var d_f_d = dateStr;
var d_f_y = dateStr;
var err_msg = '';
var d_s_day = d_f_d.slice(0, 2);
d_s_day = d_s_day + "/";
var d_s_month = d_f_m.slice(2, 4);
d_s_month = d_s_month + "/";
var d_s_year = d_f_y.slice(4, 8);
//Now we check the year to see if it is only 2 digis, if is, add 2 more
if (d_s_year.length == 2) {
d_s_year = '19' + d_s_year;
}
return d_s_day + d_s_month + d_s_year;
} else {
return null;
}
}
I've been trying to convert this function to an angularjs directive using ngModel but I just can't seem to sort it out. Would anyone know how to convert this to an angular directive?
Many thanks!
Not sure if you wanted it validated as you type or after you leave a field. Either can work, though the below is implemented to validate after you leave the field (lose focus).
The existing algorithm was used, though it looks like it handles only very specific cases (i.e. 2 digit day, 2 digit month, 2-4 digit year) and could be improved. For the moment, it was copied as is. JSFiddle is here http://jsfiddle.net/pSh4R/18/
HTML:
<div ng-app='app'>
Please enter a date
<br/>
<input type='text' dateformat ng-model='myDate'></input>
(Hit TAB when done)
<hr/>
Model Value : {{myDate}}
</div>
Directive Declaration:
var app = angular.module('app',[]);
app.directive('dateformat', function(){
return {
restrict : 'A',
scope : {
dateStr : '=ngModel'
},
link : function(scope, element){
element.bind('focusout', function (){
scope.$apply(function(){
scope.dateStr = checkValidDate(scope.dateStr);
});
});
function checkValidDate(dateStr) {
if (dateStr && dateStr != '') {
dateStr = dateStr.replace('/', '');
dateStr = dateStr.replace('/', '');
var d_f_m = dateStr;
var d_f_d = dateStr;
var d_f_y = dateStr;
var err_msg = '';
var d_s_day = d_f_d.slice(0, 2);
d_s_day = d_s_day + "/";
var d_s_month = d_f_m.slice(2, 4);
d_s_month = d_s_month + "/";
var d_s_year = d_f_y.slice(4, 8);
//Now we check the year to see if it is only 2 digis, if is, add 2 more
if (d_s_year.length == 2) {
d_s_year = '19' + d_s_year;
}
return d_s_day + d_s_month + d_s_year;
} else {
return null;
}
}
}
};
})
There are a billion ways to do what you want. Here is a quick solution I threw together to get your started:
JS:
var app = angular.module('myApp', []);
app.directive('dateValidator', function() {
return function(scope, element, attrs) {
// Watch for changes to the date model
scope.$watch('date', function(newVal, oldVal) {
if (!angular.equals(newVal, oldVal)) {
var formattedDate = checkValidDate(newVal);
if (formattedDate) {
element.text(formattedDate);
}
}
});
});
});
HTML:
<input type="text" date-validator date="myDate" ng-model="myDate" />
I recommend that you write a custom angular validator. There are some good articles on it. Here is one that I like:
Form Validation with AngularJS
The form and its containing fields have special properties appended to them that you can leverage for binding expressions and client-side validation:
$pristine, $dirty, $valid, $error

Resources