i am using angular ng-repeat to print a list but i need to make every odd letter of the word in uppercase i am sure there is a scope of it with angular js but dont know how please help.
HTML CODE
<ul ng-app="mySite" ng-controller="MyCtrl">
<li ng-repeat="list in listData">
{{list | myFormat}}
</li>
</ul>
JAVASCRIPT
var app = angular.module('mySite', []);
app.filter('myFormat', function() {
return function(list) {
var i, c, txt = "";
list= list.split("")
for (i = 0; i < list.length; i++) {
c = list[i];
if (i % 2 == 0) {
c = c.toupperCase();
}
txt += c;
}
return txt;
};
});
app.controller('MyCtrl', function($scope) {
$scope.listData = [
'Jani',
'Carl',
'Margareth',
'Hege',
'Joe',
'Gustav',
'Birgit',
'Mary',
'Kai'
];
});
such a silly mistake you are doing
toupperCase(); is wrong use toUpperCase();
Related
I am programming a calculator in AngularJS. I am stuck on a validating user input. I do not want the user to be able to enter two 2 operators ('+','/','*') next to each other.
Thus every time, I try to compare the last character and the second to last character of the string. But I always find I have two operator characters.
var app = angular.module("myApp", []);
app.controller("myCtrl", function ($scope) {
$scope.expression = "";
var liste = ['+', '/', '*'];
$scope.add = function (ope) {
$scope.expression += String(ope);
var der = $scope.expression[$scope.expression.length - 1];
var avantDer = $scope.expression[$scope.expression.length - 2];
if ($scope.expression.length > 3 && liste.includes(der) && liste.includes(avantDer)) {
alert("error");
} else {
$scope.expression += String(ope);
}
};
});
You are very close. The problem is that you are adding the operator to the expression before you have checked if it is valid or not. It is better to check the last character of the existing expression and the new character as a separate variable.
You also want to check if the length of expression is greater than 0 rather than 3 as otherwise, the user could enter two '+' characters straight away when the length is less than 3.
var app = angular.module("myApp", []);
app.controller("myCtrl", function ($scope) {
$scope.expression = "";
var liste = ['+', '/', '*'];
$scope.add = function (ope) {
// don't add to expression, just store into der
var der = String(ope);
var avantDer = $scope.expression[$scope.expression.length - 1];
if ($scope.expression.length > 0 && liste.includes(der) && liste.includes(avantDer)) {
alert("error");
} else {
$scope.expression += der;
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div>
<button ng-click="add('+')">+</button>
<button ng-click="add('*')">*</button>
<button ng-click="add('/')">/</button>
</div>
<div>
<button ng-click="add('1')">1</button>
<button ng-click="add('2')">2</button>
<button ng-click="add('3')">3</button>
</div>
{{expression}}
</div>
There were two things wrong.
$scope.expression.length > 3 should have been
$scope.expression.length > 2
You were calling $scope.expression += String(ope); twice
I made a minor change below so I could run it in the code snippet window.
I also added subtraction to liste.
var $scope = {
expression: ""
};
var liste = ['+', '/', '*', '-'];
debugger
$scope.add = function (ope) {
var temp = $scope.expression + String(ope);
console.log(temp);
var len = temp.length - 1;
if (len > 1) {
var der = temp[len];
var avantDer = temp[len - 1];
if (liste.includes(der) && liste.includes(avantDer)) {
console.log("error");
} else {
$scope.expression = temp;
}
}
else {
$scope.expression = temp;
}
};
$scope.add('3');
$scope.add('+');
$scope.add('-');
When I call $scope.add('-'); it displays the error like you expect.
I have a list of object array with id and value as its properties. Basically what I want is, the num.items[i].value should go in each div as pair. One: one and so on.
If num.items[i].id doesn't have the digit (like the array doesn't include id 3) then the id="digit_3" should be left blank.
HTML
<ul>
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>
Javascript
var num = {
items: [
{ id:4, value:"four"},
{ id:1, value:"one"},
{ id:2, value:"two"},
]
};
for(var i=0; i<num.items.length; i++){
document.getElementById("digit_"+i+1).innerHTML = i+1;
console.log(i+1)
}
Required output
One: one
Two: two
Three:
Four: four
I know we cannot compare the id digit but any modification in HTML is greatly appreciated.
it's really simple - you just have to understand arrays and objects:
var num = {
items: [{
id: 4,
value: "four"
},
{
id: 1,
value: "one"
},
{
id: 2,
value: "two"
},
]
};
var cleanableElements = document.querySelectorAll("ul li div");
for (var i = 0; i < cleanableElements.length; i++) {
cleanableElements[i].innerHTML = '';
}
var index;
for (var i = 0; i < num.items.length; i++) {
index = num.items[i].id;
document.getElementById("digit_" + index).innerHTML = num.items[i].value;
}
<ul>
<li>One:
<div id="digit_1"></div>
</li>
<li>Two:
<div id="digit_2"></div>
</li>
<li>Three:
<div id="digit_3"></div>
</li>
<li>Four:
<div id="digit_4"></div>
</li>
</ul>
Best idea would be to select all elements with querySelectorAll and setting empty before next step. You can't really detect all #digit_X id's so you can't just check for unchanged DIVs as you can't reliably detect them all.
You should loop ul li div then check id whether is in num.items.
Assuming your id format is digit_*.
var num = {
items: [
{ id:4, value:"four"},
{ id:1, value:"one"},
{ id:2, value:"two"},
]
}
function checkItems(num){
items = document.querySelectorAll('#target_div li div')
indexes = num.items.reduce( (pre, cur) => {
pre[cur.id] = cur.value
return pre
}, {}) // loop num.items then create one dict with key=id.
items.forEach(function(item){ //loop ul li div, then check whether id in dict=indexes.
let ids = item.id.split('_')
if(ids[1] in indexes){
item.innerHTML += ' #Found:'+item.id
} else {
item.innerHTML = ''
}
})
}
checkItems(num)
<ul id="target_div">
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>
I know I did something awkward but if div have already some value then above example will not work expect #sphinx answer I guess
var num = {
items: [{
id: 4,
value: "four"
},
{
id: 1,
value: "one"
},
{
id: 2,
value: "two"
},
]
};
var idsArray = [];
var valuesArray = [];
for (var value of num.items) {
idsArray.push(value.id);
valuesArray.push(value.value);
}
var maxId = Math.max(...idsArray);
for (var i = 1; i <= maxId; i++) {
if (idsArray.indexOf(i) !== -1) {
document.getElementById("digit_" + i).innerHTML = valuesArray[idsArray.indexOf(i)];
} else {
document.getElementById("digit_" + i).innerHTML = "";
}
}
div {
display: inline
}
<ul>
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>
In my application, I am masking the serial numbers by default (using a custom filter in angular). When the user clicks on 1 particular masked serial number, the mask needs to be removed.
Here is my code so far:
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', [ '$scope', function($scope){
$scope.name = 'Superhero';
$scope.serialNumbers = [
{serial: 12345678},
{serial: 22245678},
{serial: 33345678},
];
}]);
myApp.filter('mask', function() {
return function(input) {
var inputArray = input.toString().split('');
for (var i = 2, l = inputArray.length; i < l - 2; i++) {
inputArray[i] = '*'; // replace
}
return inputArray.join('');
};
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-app='myApp'>
<div ng-controller="MyCtrl">
Hello, {{name}}!
<p>Below are your serial numbers:</p>
<p ng-repeat="serialNumber in serialNumbers">{{serialNumber.serial | mask}}</p>
</div>
</body>
</html>
How do I achieve this?
Not totally sure I understand issue but you can use an argument in the filter and for simplicity bind it to a property of the object
myApp.filter('mask', function() {
return function(input, noMask) {
if(noMask){
return input;
}
var inputArray = input.toString().split('');
for (var i = 2, l = inputArray.length; i < l - 2; i++) {
inputArray[i] = '*'; // replace
}
return inputArray.join('');
};
});
Then in html do something like:
<p ng-repeat="serialNumber in serialNumbers"
ng-click="serialNumber.noMask=!serialNumber.noMask">
{{serialNumber.serial | mask: serialNumber.noMask }}
</p>
I am trying to achieve two things:
Bind an array to a list of checkboxes (just a string array), and
Limit the number of selections the user can make to a number between
1 and the number of available items less 1.
I can get (2) to work until the user clicks the last item, at which point it loses track and the items remain selected.
The interactive code is up here: http://codepen.io/adamcodegarden/pen/bdbQqe (forked from a similar example)
My HTML/Angular code:
<p ng-repeat="item in allOptions" class="item" id="{{item}}">
{{item}} <input type="checkbox" ng-change="sync(bool, item)" ng-model="bool" ng-checked="isChecked(item)"> Click this to sync this item with the target array. {{item}} Selected: {{bool}}
and the JS:
var myApp = angular.module("myApp", []);
var maxItems = 1;
myApp.controller('myController', function($scope) {
$scope.isChecked = function(item){
var match = false;
for(var i=0 ; i < $scope.data.length; i++) {
if($scope.data[i] === item) {
match = true;
}
}
return match;
};
$scope.allOptions = [
'one', 'two', 'three', 'four'
];
$scope.data = [
];
$scope.sync = function(bool, item){
if (bool) {
// add item
$scope.data.push(item);
// if we have gone over maxItems:
if ($scope.data.length > maxItems) {
//remove oldest item
$scope.data.splice(0,1);
}
} else {
// remove item
for (var i=0 ; i < $scope.data.length; i++) {
if ($scope.data[i] === item){
$scope.data.splice(i,1);
}
}
}
};
});
I like plunker more than codepen. So I created this plunker
http://plnkr.co/edit/l8gxQHXBQdFeKIuwf3f0?p=preview
The main idea is that I format the original array as:
$scope.allOptions = [
{key: 'one'}, {key: 'two'}, {key: 'three'}, {key:'four'}
];
And slight change to the sync logic as well:
$scope.sync = function(bool, item){
if (bool) {
// add item
$scope.data.push(item);
// if we have gone over maxItems:
if ($scope.data.length > maxItems) {
//remove first item
$scope.data[0].checked = false;
$scope.data.splice(0,1);
}
} else {
// remove item
for (var i=0 ; i < $scope.data.length; i++) {
if ($scope.data[i] === item) {
$scope.data.splice(i,1);
}
}
}
};
Also change html portion:
<p ng-repeat="item in allOptions" class="item" id="{{item.key}}">
{{item.key}} <input type="checkbox" ng-change="sync(item.checked, item)" ng-model="item.checked"> Click this to sync this item with the target array. {{item.key}} Selected: {{bool}}
Okay. I'm pulling together a data table that is going to look through majors and minors of a school. I'm running into issues of trying not to repeat myself in the data where every possible, but am not sure how to get the data pulled into the document, or even how to setup the data into the different arrays. Looking for some advice and help in whichever of these two areas I can find. When I search through docs and API's none of them seem to go deep enough into the data to really get what I'm looking to accomplish.
I have made a plunker to showcase my problem more clearly, or at least I hope to make it clearer.
http://plnkr.co/edit/2pDmQKKwjO6KVullgMm5?p=preview
EDIT:
It would even be okay with me if the degree each degree could be read as a boolean, and same with Education level. I'm just not sure how to go about it without repeating the whole line in a new table row. http://www.clemson.edu/majors
HERE IS THE HTML
<body ng-app="app">
<h2> Majors and Minors </h2>
<table ng-controller="MajorsCtrl">
<tbody>
<tr>
<th>Department</th>
<th>Major</th>
<th>Education Level</th>
<th>Location </th>
<th>Degree</th>
<th>Department Website </th>
</tr>
<tr ng-repeat="major in majors">
<td>{{major.Department}}</td>
<td>{{major.Major}}</td>
<td>{{major.EdLevel}}</td>
<td>{{major.Type}}</td>
<td>{{major.Degree}}</td>
<td>{{major.Website}}</td>
</tr>
</tbody>
</table>
</body>
HERE IS THE JS
var app = angular.module('app', []);
// Majors and Minors Data That will be injected into Tables
app.controller('MajorsCtrl', function($scope) {
// Heres where it gets tricky
// Now I have biology with four diff degree types
// Biology with 2 diff EdLevels
// How do I combine all of these into 1 Group without repeating
var majorsInfo = [
{
Department:'Statistics',
Major:'Applied Statitistics',
EdLevel:'Graduate',
Type:'Campus/Online',
Degree:'Graduate Certificate',
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Graduate',
Type:'Campus',
Degree:'PH.D' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Graduate',
Type:'Campus',
Degree:'M.S' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Undergraduate',
Type:'Campus',
Degree:'B.A.' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Undergraduate',
Type:'Campus',
Degree:'B.S.' ,
Website: 'http://biology.wvu.edu',
},
];
$scope.majors = majorsInfo;
});
This seems to be a question about modeling the data. I took a few assumptions:
A department can offer multiple majors
A department has a website
Each major can offer one to many Educations (i.e. Education Level, On/Off Campus, Degree)
The department can offer multiple minors with the same data structure as majors
I modeled a set of "enums" and Programs/Departments after your data. I used enums for ease of updating the values in multiple locations:
app.factory("EducationEnums", function () {
var EdLevels = {
GRAD: "Graduate",
UGRAD: "Undergraduate"
};
var Types = {
CAMPUS: "Campus",
ONLINE: "Online",
HYBRID: "Campus/Online"
};
var Degrees = {
PHD: "PH.D",
MS: "M.S.",
BS: "B.S.",
BA: "B.A.",
GCERT: "Graduate Certificate"
};
return {
EdLevels: EdLevels,
Types: Types,
Degrees: Degrees
}
});
app.factory("Programs", function (EducationEnums) {
var EdLevels = EducationEnums.EdLevels;
var Types = EducationEnums.Types;
var Degrees = EducationEnums.Degrees;
return [
{
Department: "Biology",
Website: "http://biology.wvu.edu",
//Majors offered by department
Majors: [{
Major: "Biology",
Education: [
{
EdLevel: EdLevels.GRAD,
Type: Types.CAMPUS,
Degree: Degrees.PHD
},
{
EdLevel: EdLevels.GRAD,
Type: Types.CAMPUS,
Degree: Degrees.MS
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BA
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BS
}
]
}],
Minors: [{
//Minors can go here
}]
},
{
Department: "Statistics",
Website: "http://biology.wvu.edu",
Majors: [{
Major: "Applied Statistics",
Education: [
{
EdLevel: EdLevels.GRAD,
Type: Types.HYBRID,
Degree: Degrees.GCERT
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BS
}
]
}],
Minors: [{
//Minors can go here
}]
}
]
});
Next, I made a Majors service that uses this Programs data to build ViewModels (to be bound to scope in the controllers). Here you can build your original table, or you can build a matrix (like the Clemson site):
app.service("Majors", function (Programs, EducationEnums) {
var Degrees = this.Degrees = EducationEnums.Degrees;
//Build ViewModel for all details
this.getMajorDetails = function () {
var arr = [];
var programLen;
var majorLen;
var eduLen;
for (var i = 0; i < (programLen = Programs.length); ++i) {
var p = Programs[i];
var dept = p.Department;
var ws = p.Website;
var Majors = p.Majors;
for (var j = 0 ; j < (majorLen = Majors.length); ++j) {
var maj = Majors[j].Major;
var edu = Majors[j].Education;
for (var k = 0; k < (eduLen = edu.length); ++k) {
arr.push({
Department: dept,
Major: maj,
EdLevel: edu[k].EdLevel,
Type: edu[k].Type,
Degree: edu[k].Degree,
Website: ws
});
}
}
}
return arr;
}
//Build ViewModel for Degrees offered (similar to Clemson)
this.getMajorMatrix = function () {
var arr = [];
var programLen;
var majorLen;
var eduLen;
for (var i = 0; i < (programLen = Programs.length); ++i) {
var p = Programs[i];
var Majors = p.Majors;
for (var j = 0; j < (majorLen = Majors.length); ++j) {
var maj = Majors[j].Major;
var edu = Majors[j].Education;
var obj = {
Major: maj
};
for (var k = 0; k < (eduLen = edu.length); ++k) {
var degree = edu[k].Degree;
if (degree === Degrees.PHD) {
obj.PHD = true;
}
else if (degree === Degrees.MS) {
obj.MS = true;
}
else if (degree === Degrees.BS) {
obj.BS = true;
}
else if (degree === Degrees.BA) {
obj.BA = true;
}
}
arr.push(obj);
}
}
return arr;
}
});
Your controller can just call the Majors service methods to bind the ViewModel to the $scope:
app.controller('MajorsCtrl', function($scope, Majors) {
$scope.majorDetails = Majors.getMajorDetails();
});
app.controller("MajorMatrixCtrl", function ($scope, Majors) {
$scope.Degrees = Majors.Degrees;
$scope.majorMatrix = Majors.getMajorMatrix();
});
Separting like this would allow you to later update the Programs factory to not just use static data, but could pull from a service via $http for instance. The Programs data can be manipulated to achieve your desired ViewModel through the Majors service (and Minors service if you choose to write a separate one).
Updated Plunkr