Making calculations from nested arrays in AngularJS - javascript

I have the following array:
$scope.products = [
{
nom : "Pa de fajol",
img : "dill1.jpg",
descripcio: [
"Pa de motlle"
],
preu:4.90,
tipus: "Pa"
},
{
nom : "Pagès semi integral de blat/espelta",
img : "dill2.jpg",
descripcio: [
"Pa de pagès",
"680g / 400g"
],
tipus: "Pa",
variacions : [
{
nom: "Gran",
preu: "3.70",
grams: "680g",
basket: 0
},
{
nom: "Petit",
preu: "2.30",
grams: "400g",
basket: 1
}
]
}
In the frontend I display it with an ng-repeat and depending if the product has price (preu) or not, I display one input for quantity for single product, or one input for each variation.
Looks like this:
<div ng-repeat="pa in products">
<div ng-if="!pa.preu" ng-repeat="vari in pa.variacions">
<input type="number" ng-model="pa.variacions.basket" ng-init="pa.variacions.basket=0">
</div>
<input ng-if="pa.preu" type="number" ng-model="pa.basket" name="basket" ng-init="pa.basket=0">
</div>
<a ng-click="insert()">Add to cart</a>
When I trigger insert(), I have a function that will add the products and calculate the total price, but so far it only works for products with a price, not for the variations.
The function looks like this:
$scope.insert = function() {
$scope.singleorder = [];
for(var i = 0; i < $scope.products.length; i++)
if($scope.products[i].basket) { // if input has been setted
$scope.singleorder.push({
'product': $scope.products[i].nom,
'number': $scope.products[i].basket,
'preu': ($scope.products[i].preu * $scope.products[i].basket)
});
}
console.log($scope.singleorder);
}
How would I have to proceed to include in the $scope.singleorder array also the calculations from the nested array of variations?
Any tips?
EDIT
See Plunkr to reproduce the issue
SOLUTION
I managed to fix it with the help of some comments!
See Plunkr for final version.
Here's the final function:
$scope.insert = function() {
$scope.singleorder = [];
for(var i = 0; i < $scope.products.length; i++)
if($scope.products[i].basket) { // if input has been setted
$scope.singleorder.push({
'product': $scope.products[i].nom,
'number': $scope.products[i].basket,
'preu': ($scope.products[i].preu * $scope.products[i].basket)
});
}
else if($scope.products[i].variacions) { // if input has been setted
angular.forEach($scope.products[i].variacions, function(variacions) {
if(variacions.basket) {
$scope.variname = $scope.products[i].nom + ' (' + variacions.nom + ')'
$scope.singleorder.push({
'product': $scope.variname,
'number': variacions.basket,
'preu': (variacions.preu * variacions.basket)
});
}
});
}
console.log($scope.singleorder);

Your issue was that your variacions is an array use this,
$scope.insert = function() {
$scope.singleorder = [];
for(var i = 0; i < $scope.products.length; i++)
if($scope.products[i].basket) { // if input has been setted
$scope.singleorder.push({
'product': $scope.products[i].nom,
'number': $scope.products[i].basket,
'preu': ($scope.products[i].preu * $scope.products[i].basket)
});
}
else if($scope.products[i].variacions) { // if input has been setted
for(var j=0;j<$scope.products[i].variacions.length; j++){
$scope.singleorder.push({
'product': $scope.products[i].variacions[j].nom,
'number': $scope.products[i].variacions[j].basket,
'preu': ($scope.products[i].variacions[j].preu * $scope.products[i].variacions[j].basket)
});
}
}
console.log($scope.singleorder);
}
See Plunkr

Related

infinite algorithm. javascript

i'm pretty new to js. i'm sorry if this sounds dumb.I have such an algorithm for javascript. when executed, it loops. Why? What is his mistake?
I have such source data
enter image description here
let incomesArray = [];
incomesArray[0] = {
income_id: incomeList[0].id,
worker_id: incomeList[0].worker_id,
worker_surname: incomeList[0].worker_surname,
worker_name: incomeList[0].worker_name,
incomeList: [
{
provider_name: incomeList[0].provider_name,
product_category: incomeList[0].product_category_name,
product_name: incomeList[0].product_name,
product_count: incomeList[0].product_count,
purchase_price: incomeList[0].purchase_price
}
],
incomeDate: incomeList[0].date,
total: incomeList[0].total
}
if(incomesArray.length > 0 ){
for(let i = 1; i < incomeList.length; i++) {
for(let j = 0; j < incomesArray.length; j++){
if(incomeList[i].id == incomesArray[j].id){
for(let k = 0; k < incomesArray[j].incomeList.length; k++){
incomesArray[j].incomeList.push({
provider_name: incomeList[i].provider_name,
product_category:
incomeList[i].product_category_name,
product_name: incomeList[i].product_name,
product_count: incomeList[i].product_count,
purchase_price: incomeList[i].purchase_price
})
}
} else if (incomesArray[j].id !== incomeList[i].id) {
incomesArray.push({
income_id: incomeList[i].id,
worker_id: incomeList[i].worker_id,
worker_surname: incomeList[i].worker_surname,
worker_name: incomeList[i].worker_name,
incomeList: [
{
provider_name: incomeList[i].provider_name,
product_category: incomeList[i].product_category_name,
product_name: incomeList[i].product_name,
product_count: incomeList[i].product_count,
purchase_price: incomeList[i].purchase_price
}
],
incomeDate: incomeList[i].date,
total: incomeList[i].total
})
}
}
}
}
I will be grateful for any help or hint.
It's your else part that causes the problem. For every item in incomesArray that has a different id than the item in incomeList you add another entry to incomesArray; while you're iterating over that array. Like this gif:
Extending the track while you're driving on it.
Second, your comparison: if(incomeList[i].id == incomesArray[j].id) but incomesArray[j] has no id, only a income_id, so you'll always run into the else part where you add more items to incomesArray.
I've restructured your code a bit:
const incomesArray = [];
for (const row of incomeList) {
let target = incomesArray.find(item => item.income_id === row.id);
if (!target) {
incomesArray.push(target = {
income_id: row.id,
worker_id: row.worker_id,
worker_surname: row.worker_surname,
worker_name: row.worker_name,
incomeList: [],
incomeDate: row.date,
total: row.total
});
}
target.incomeList.push({
provider_name: row.provider_name,
product_category: row.product_category_name,
product_name: row.product_name,
product_count: row.product_count,
purchase_price: row.purchase_price
});
}

numbers not getting added together node js

I am trying to store prices of products in sessions, and if a product is clicked twice, the price is should be added and shown in the session, but for some reason when I am trying to add two number , for example 15 + 15, it adds like 01515, I am not sure why this is happening.
Here is the .hbs file where the addition of a product starts.
{{# each products}}
<div class="row">
{{# each this}}
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="{{this.imagePath}}" alt="..." class="img-responsive">
<div class="caption">
<h3>{{this.title}}</h3>
<p>{{this.description}}</p>
<div class="clearfix">
<div class="price pull-left">${{this.price}}</div>
Add to cart
</div>
</div>
</div>
</div>
{{/each}}
</div>
{{/each}}
After add to cart button is pressed, here is the route and model,
route
router.get('/add-to-cart/:id', function(req, res, next) {
var productId = req.params.id;
var cart = new Cart(req.session.cart ? req.session.cart : {});
Product.findById(productId, function(err, product) {
if (err) {
return res.redirect('/');
}
cart.add(product, product.id);
req.session.cart = cart;
console.log(req.session.cart);
res.redirect('/');
});
});
Model
module.exports = function Cart(oldCart) {
this.items = oldCart.items || {};
this.totalQty = oldCart.totalQty || 0;
this.totalPrice = oldCart.totalPrice || 0;
this.add = function(item, id) {
var storedItem = this.items[id];
if (!storedItem) {
storedItem = this.items[id] = {item: item, qty: 0, price: 0};
}
storedItem.qty++;
storedItem.price = storedItem.item.price * storedItem.qty;
this.totalQty++;
this.totalPrice += storedItem.item.price;
};
this.generateArray = function() {
var arr = [];
for (var id in this.items) {
arr.push(this.items[id]);
}
return arr;
};
};
I tried to log in the console to see whats happening while adding the numbers, it shows like this
Cart {
items:
{ '5855c55482d8722419e21a7d': { item: [Object], qty: 1, price: 15 },
'5855c55482d8722419e21a7f': { item: [Object], qty: 1, price: 15 } },
totalQty: 2,
totalPrice: '01515',
add: [Function],
reduceByOne: [Function],
removeItem: [Function],
generateArray: [Function] }
I am very new to node js, and I am not sure what is going wrong with this.
In your module, change this line
this.totalPrice = oldCart.totalPrice || 0;
to be something like this
this.totalPrice = parseInt(oldCart.totalPrice, 10) || 0;
You should also change
this.totalPrice += storedItem.item.price;
to be something like
this.totalPrice += parseInt(storedItem.item.price);
The issue here is that both this.totalPrice and storedItem.item.price are strings when you first get it from your request — this.totalPrice being a string because oldCart.totalPrice will come back to you as a string.
This is causing coercion on your storedItem.item.price to a string when you add them together:
this.totalPrice += storedItem.item.price;
// string += string => concatenated string
oldcart.totalPrice would be giving you string so the value are getting concatenated.
instead of
this.totalPrice = oldCart.totalPrice || 0;
you could use
this.totalPrice = Number(oldCart.totalPrice) || 0;
Its seems you concat a string value !
try to cast/force the integer type before do any mathematical action
const string1 = '123'
const string2 = '233'
console.log(string1 + string2) //123233
console.log(parseInt(string1) + parseInt(string2)) //356
Always verify if your parseInt do not return a NaN ;)

Calculation does not return the correct value

can anyone tell me what is the error on this javascript code?
Program: http://utilizaweb.com.br/aposentadorianovo/
function calcula(){
var fieldsContainer=document.getElementsByClassName("trabalho")[0].
getElementsByClassName("row"),
i,
jobFields=[],
len,
newAge=0,
selfGender=document.aposentadoria.sexo.value,
workedDays=0,
workedMonthies=0,
workedYears=0;
len=fieldsContainer.length;
for(i=0;len>i;i++){
jobFields[i]={
admissionDate:new Date(fieldsContainer[i].getElementsByClassName("admissao-area")[0].children[1].value),//data de admissão,
ageRule:fieldsContainer[i].getElementsByClassName("regra-area")[0].children[0].value,//regra
demissionDate:new Date(fieldsContainer[i].getElementsByClassName("demissao-area")[0].children[1].value),//data de demissão
jobBusiness:fieldsContainer[i].getElementsByClassName("empresa-area")[0].children[1].value//empresa do trabalho
};
if (jobFields[i].demissionDate > jobFields[i].admissionDate) {
jobFields[i].workedYears=jobFields[i].demissionDate.getFullYear() - jobFields[i].admissionDate.getFullYear();
jobFields[i].workedMonthies=jobFields[i].demissionDate.getMonth() - jobFields[i].admissionDate.getMonth();
jobFields[i].workedDays=jobFields[i].demissionDate.getDate() - jobFields[i].admissionDate.getDate();
alert(jobFields[i].workedYears)
} else {
alert("A data de admissão deve ser anterior à data de demissão.");
throw new Error("Conversor :: Admission date must be older than demission date.")
}
}
var fieldsRule=[];
len=jobFields.length;
for(i=0;len>i;i++){
fieldsRule[i]=jobFields[i].ageRule
}
var calculateFields=[],
higherRule=Math.max.apply(fieldsRule)
len=jobFields.length;
for(i=0;len>i;i++){
if(fieldsRule[i]===higherRule){
calculateFields[i]=i
}
}
var ageMultiplyBy,
missingYears,
jobYearsEnd;
len=calculateFields.length;
if (selfGender === "M") {
for(i=0;len>i;i++){
ageMultiplyBy=
jobFields[calculateFields[i]].ageRule==="25"?1.40:
jobFields[calculateFields[i]].ageRule==="20"?1.75:
jobFields[calculateFields[i]].ageRule==="15"?2.33:
1.75;
newAge=jobFields[calculateFields[i]].workedYears*ageMultiplyBy;
missingYears=newAge - 35
}
} else {
for(i=0;len>i;i++){
ageMultiplyBy=
jobFields[calculateFields[i]].ageRule==="25"?1.20:
jobFields[calculateFields[i]].ageRule==="20"?1.50:
jobFields[calculateFields[i]].ageRule==="15"?2:
1.20;
newAge=jobFields[calculateFields[i]].workedYears*ageMultiplyBy;
missingYears=newAge - 30
}
}
alert(missingYears)
if (missingYears < 0) {
jobYearsEnd=missingYears * -1;
}
document.getElementById("anosTrabalhados").innerHTML = workedYears+ " anos";
document.getElementById("result").innerHTML = "<img src='./img/aviso.png'>" +"Você trabalhou " +workedYears+ " anos, " +workedMonthies+ " meses e " +workedDays+ " dias"+ "<br />" +"Faltam " +jobYearsEnd+ " anos para se aposentar"
}
[IF WASN'T WELL EXPLAINED, PLEASE TELL ME. I DONT SPEAK ENGLISH SO WELL]
I need get the value of the admissionDate and of the demissionDate and subtract of each line, including those added by the user. Then, I need get the biggest values of rules are equal, and add up the time worked in each one. Then, the program takes the time worked added up and multiply by the value of each rule and subtract of 35 in case of male and of 30 in case of female. And then displays the value calculated last (minus 30 or 35).
Where the code is wrong?
Look the code by View Source
I did what I could with this one as there are several challenges and a couple of points where I am not 100 percent sure your intent. I believe you can work from here. Date stuff is hard when you work with multiple related dates. What if the boundary crosses daylight savings time etc. To assist with that I used a date library, feel free to get another or use it, I pasted it into the fiddle code; use it or get another that does that stuff rather than re-invent one. I did not use it extensively.
Here is a saved fiddle to test/try it out: (see the bottom for the good parts) https://jsfiddle.net/MarkSchultheiss/1ttmecoe/
Link the the date library: http://slingfive.com/pages/code/jsDate/jsDate.html
Explanation:
First off, your undisclosed code replicates an ID and those MUST be unique, and when you use that it is in error. I fixed that by using jQuery .clone() I also put a method to add/remove rows (all but last one) from your list) which was lacking on your page.
Code snip:
document.getElementById("anosTrabalhados").innerHTML
I will show you how to fix that (see the markup and .clone())
You have some rather complex selectors which can be simplified by the use of classes.
Code snip:
jobFields[i]={
admissionDate:new Date(fieldsContainer[i].getElementsByClassName("admissao-area")[0].children[1].value),//data de admissão,
revised:
var thisRow = fieldsContainer[i];
jobFields[i] = {
admissionDate: new Date(thisRow.getElementsByClassName("dataAdmissao")[0].value),
Checking/validation of dates right in the middle of a loop, perhaps you might check those before you loop? I left that for now as it was.
Code snip:
if (jobFields[i].demissionDate > jobFields[i].admissionDate) {
This appears to be a syntax issue here:
higherRule=Math.max.apply(fieldsRule) //old
higherRule=Math.max.apply(null, fieldsRule); //repaired
ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
Remove constants from code and put them in an object:
Code snip:
var calcVals = {
rules: {
male: {
sex: "M",
defaultRate: 1.75,
ageVar: 35,
ageRules: [{
age: "25",
val: 1.40
}, {
age: "20",
val: 1.75
}, {
age: "15",
val: 2.33
}]
},
female: {
sex: "M",
defaultRate: 1.50,
ageVar: 30,
ageRules: [{
age: "25",
val: 1.20
}, {
age: "20",
val: 1.50
}, {
age: "15",
val: 2.00
}]
}
}
};
then use it later: (this gets rid of the duplicate hard coded conditional making it simpler and more maintainable)
calcT = (selfGender === "M") ? calcT = calcVals.rules.male : calcT = calcVals.rules.female;
ageMultiplyBy = calcT.defaultRate;
for (i = 0; len > i; i++) {
for (var j = 0; j < calcT.ageRules.length; j++) {
if (jobFields[calculateFields[i]].ageRule === calcT.ageRules[j].age) {
ageMultiplyBy = calcT.ageRules[j].val;
break;
}
}
...more code
Assignment of a string to an array
Code snip:
fieldsRule[i]=jobFields[i].ageRule
This changes this comparison: (see the next code segment as well)
if(fieldsRule[i]===higherRule){
The fieldsRule[i] is a string and higherRule is a numeric (see the Math.max.apply above)
You set the iteration variable len based on jobFields but access the fieldsRule[i] which MIGHT be undefined. Did you mean to push to the array rather than assign to it? I ask because later on you use len=calculateFields.length; as an iterate value. Note that all the fieldsRule[i] might not be evaluated if the lengths differ on the arrays OR it might have an undefined value. (note that this is where your desired functionality becomes less clear)
len=jobFields.length;
for(i=0;len>i;i++){
if(fieldsRule[i]===higherRule){
calculateFields[i]=i
}
}
See this later down: newAge=jobFields[calculateFields[i]].workedYears*ageMultiplyBy; where calculateFields[i] might be undefined.
Revised markup:
<form class="form-calculadora" name="aposentadoria">
<fieldset class="sexo">
<legend>Sexo</legend>
<select id="sexo" class="text-area">
<option value="M">Masculino</option>
<option value="F">Feminino</option>
</select>
</fieldset>
<fieldset class="trabalho">
<div class="row p_scents">
<div class="empresa-area">
<p class="title">Empresa</p>
<input type="text" class="text-area empresa" placeholder="Empresa: ">
</div>
<div class="regra-area">
<p class="title">Regra</p>
<select class="text-area regra">
<option value="25">25 anos</option>
<option value="20">20 anos</option>
<option value="15">15 anos</option>
</select>
</div>
<div class="admissao-area">
<p class="title">Admissão</p>
<input type="date" class="text-area dataAdmissao" placeholder="Admissão: " />
</div>
<div class="demissao-area">
<p class="title">Demissão</p>
<input type="date" class="text-area dataDemissao" placeholder="Demissão: " />
</div>
<div class="anos-area">
<p class="anosTrabalhados">0 anos</p>
</div>
<button class="removerow">
Remove Row
</button>
</div>
</fieldset>
<p class="add-empresa"><i class="fa fa-user-plus"></i> Adicionar Empresa</p>
<p id="result">Você trabalhou 0 anos, 0 meses e 0 dias
<br/>Faltam undefined anos para se aposentar</p>
<input type="button" value="Calcular" class="btn" id="calcular" />
</form>
Revised code:
var calcVals = {
rules: {
male: {
sex: "M",
defaultRate: 1.75,
ageVar: 35,
ageRules: [{
age: "25",
val: 1.40
}, {
age: "20",
val: 1.75
}, {
age: "15",
val: 2.33
}]
},
female: {
sex: "M",
defaultRate: 1.50,
ageVar: 30,
ageRules: [{
age: "25",
val: 1.20
}, {
age: "20",
val: 1.50
}, {
age: "15",
val: 2.00
}]
}
}
};
function calcula() {
var rows = $('.row');
var fieldsContainer = document.getElementsByClassName("trabalho")[0].
getElementsByClassName("row"),
i,
jobFields = [],
len,
newAge = 0,
selfGender = document.aposentadoria.sexo.value,
workedDays = 0,
workedMonthies = 0,
workedYears = 0;
var fieldsRule = [];
var calculateFields = [],
len = fieldsContainer.length;
for (i = 0; i < len; i++) {
var thisRow = fieldsContainer[i];
jobFields[i] = {
admissionDate: new Date(thisRow.getElementsByClassName("dataAdmissao")[0].value),
demissionDate: new Date(thisRow.getElementsByClassName("dataDemissao")[0].value),
ageRule: thisRow.getElementsByClassName("regra")[0].value,
jobBusiness: thisRow.getElementsByClassName("empresa")[0].value
};
// console.dir(jobFields);
if (jobFields[i].demissionDate > jobFields[i].admissionDate) {
jobFields[i].workedYears = Date.DateDiff('yyyy', jobFields[i].admissionDate, jobFields[i].demissionDate);
// get months after remove years
jobFields[i].workedMonthies = Date.DateDiff('m', jobFields[i].admissionDate, jobFields[i].demissionDate) - (jobFields[i].workedYears * 12);
// console.log('days:' + Date.DateDiff('d', jobFields[i].admissionDate, jobFields[i].demissionDate) );
// get days worked after remove years/months
var adate = new Date(jobFields[i].demissionDate);
adate = new Date(adate.setFullYear(jobFields[i].demissionDate.getFullYear() - jobFields[i].workedYears));
adate = new Date(adate.setMonth((adate.getMonth()) - jobFields[i].workedMonthies));
jobFields[i].workedDays = Date.DateDiff('d', jobFields[i].admissionDate, adate); //- (new Date(jobFields[i].admissionDate) - new Date(jobFields[i].demissionDate));
// console.log('worked' + i + ":" + jobFields[i].workedYears);
} else {
alert("A data de admissão deve ser anterior à data de demissão. not less");
// throw new Error("Conversor :: Admission date must be older than demission date.")
}
}
len = jobFields.length;
for (i = 0; len > i; i++) {
fieldsRule[i] = +jobFields[i].ageRule;
}
var higherRule = Math.max.apply(null, fieldsRule);
console.log("higherRule:" + higherRule + " fLen:" + fieldsRule.length);
len = jobFields.length;
console.dir({
"jobf": jobFields
});
//console.dir(fieldsRule);
for (i = 0; i < len; i++) {
if (fieldsRule[i] === higherRule) {
calculateFields[i] = i;
}
}
console.dir({
"calcf": calculateFields
});
var ageMultiplyBy,
missingYears,
jobYearsEnd;
console.dir(fieldsRule);
len = calculateFields.length;
var calcT = {};
calcT = (selfGender === "M") ? calcT = calcVals.rules.male : calcT = calcVals.rules.female;
ageMultiplyBy = calcT.defaultRate;
for (i = 0; len > i; i++) {
for (var j = 0; j < calcT.ageRules.length; j++) {
if (jobFields[calculateFields[i]].ageRule === calcT.ageRules[j].age) {
ageMultiplyBy = calcT.ageRules[j].val;
break;
}
}
newAge = jobFields[calculateFields[i]].workedYears * ageMultiplyBy;
missingYears = newAge - calcT.ageVar;
}
console.log('mys:' + missingYears);
if (missingYears < 0) {
jobYearsEnd = (+missingYears) * -1;
}
len = jobFields.length;
for (i = 0; i < len; i++) {
workedYears = workedYears + jobFields[i].workedYears;
workedMonthies = workedMonthies + jobFields[i].workedMonthies;
workedDays = workedDays + jobFields[i].workedDays;;
}
//invalid id cannot be dupe document.getElementById("anosTrabalhados").innerHTML = workedYears + " anos";
for (var m = 0; m < rows.length; m++) {
console.log('wy:' + workedYears);
$('.row').eq(m).find('.anosTrabalhados').text(workedYears + " anos");
}
// document.getElementById("anosTrabalhados").innerHTML = workedYears + " anos";
document.getElementById("result").innerHTML = "<img src='./img/aviso.png'>" + "Você trabalhou " + workedYears + " anos, " + workedMonthies + " meses e " + workedDays + " dias" + "<br />" + "Faltam " + jobYearsEnd + " anos para se aposentar"
}
$(function() {
// set defaults for testing
makedefaults(0);
$('#calcular').on('click', function() {
calcula();
});
// add a row
$('#addScnt').on('click', function(e) {
var rowContainer = $('.trabalho');
var rows = rowContainer.find('.row');
var newRow = rows.eq(0).clone(true);
rowContainer.append(newRow);
e.preventDefault();
return false;
});
// remove any row but last one
$('.trabalho').on('click', '.removerow', function(e) {
var rowsCount = $('.trabalho').find('.row').length;
if (rowsCount > 1) {
$(this).parents('.row').remove();
}
e.preventDefault();
return false;
});
});

Angular JS: Multiple Data Bindings Into Table

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

Find element by data attributes that use "|" as separators

Fiddle Example
HTML markup:
<div data-id='23|24|25'></div>
<div data-id='29|30|31'></div>
Script:
var array = [
{
"mid": "24"
},
{
"mid": "26"
},
{
"mid": "28"
},
{
"mid": "29"
},
{
"mid": "30"
},
{
"mid": "31"
}
];
var item_html ="";
$.each(array,function(i,k) {
item_html = '<h3>'+k["mid"]+'</h3>';
$('div[data-id="'+k["mid"]+'"').append(item_html); ???????????
});
Would it be possible to find the div element if part of the "|" separated value in its data-id matches the mid?
I'm trying to get an output like this:
<div data-id='23|24|25'>
<h3>24</h3>
</div>
<div data-id='29|30|31'>
<h3>29</h3>
<h3>30</h3>
<h3>31</h3>
You should use the *= selector (contains):
$('div[data-id*="'+k["mid"]+'"').append(item_html);
The result you are looking for is something tricky. I have update your code. hope this will help you.
var array = [
{ "mid": "24"},
{"mid": "26"},
{"mid": "28"},
{"mid": "29"},
{"mid": "30"},
{"mid": "31"}
];
$('[data-id]').each(function(){
var $this = $(this), dataArr = $this.data('id').split('|'), i = 0;
for(;i< dataArr.length; i++) {
if(numInObjArr(array,dataArr[i])) {
$this.append('<h3>'+ dataArr[i] +'</h3>');
}
}
});
//function to check number in array object provided above
function numInObjArr(objArr, num){
for (var i = 0, len=objArr.length; i< len; i++){
if(objArr[i]["mid"] == num) {
return true;
}
}
return false;
}
http://jsfiddle.net/EZ56N/73/ to see the working example

Categories

Resources