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
Related
I have a custom section called layout_category_id, which lists a series of items. The mentioned items are 4 in total and each one has its respective id.
What I am trying to do is that when the id of layout_category_id is different from 1, no discount can be applied.
I made a code in js that makes that comparison that works only at a visual level ... well, even if the discount is assigned or equal, it continues to apply the discount if it was previously added.
`
_computeAggregates: function () {
var self = this;
var data = [];
var datos = 0;
try {
datos = this.state.data.length;
if (datos >= 0) {
for (var i = 0; i < datos; i++) {
if (this.state.data[i]['data'].layout_category_id.data) {
// preguntamos si es distinto a alquileres
if (this.state.data[i]['data'].layout_category_id.data.id != 1) {
this.state.data[i]['data']['discount'] = 0.00;
}
// console.log(this.state.data[i]['data']);
}
}
}
} catch(err) {
console.log(err.message);
}
if (this.selection.length) {
console.log('entro mal');
utils.traverse_records(this.state, function (record) {
if (_.contains(self.selection, record.id)) {
data.push(record); // find selected records
}
});
} else {
// xnet
data = this.state.data;
}
_.each(this.columns, this._computeColumnAggregates.bind(this, data));
},
`
Initially I wanted to do it in XML in this way but obviously it did not work
<field t-if="layout_category_id == 1" name="discount" class="descuento" groups="sale.group_discount_per_so_line"/>
I'm trying to display one pie chart for each question from my database. Right now, I am only able to display one chart on the first question.
I don't know how to display charts for the rest of the questions. I'm also not sure if I'm doing it the right way? I'm currently using ViewBag to pass the data from controller. How do I do it properly?
Please help me. Thanks.
This is my View:
<table class="table">
<tr>
<th>
Questions
</th>
</tr>
#foreach (var question in (List<Testv3.Models.MyViewModel>)ViewData["questionlist"])
{
<tr>
<td>
#question.Question
<br />
<div class="chart">
<canvas id="pie-chart"></canvas>
</div>
</td>
</tr>
}
</table>
#section Scripts {
<script type="text/javascript">
var PieChartData =
{
labels: ["Agree", "Somewhat Agree", "Disagree"],
datasets: [{
label: 'Overall report',
backgroundColor: [
"#f990a7",
"#aad2ed",
"#9966FF",
],
borderWidth: 2,
data: [#ViewBag.countAgree, #ViewBag.countSomewhatAgree, #ViewBag.countDisagree]
}]
};
window.onload = function () {
var ctx1 = document.getElementById("pie-chart").getContext("2d");
window.myBar = new Chart(ctx1,
{
type: 'pie',
data: PieChartData,
options:
{
responsive: true,
maintainAspectRatio: true
}
});
}
</script>
This is my controller:
List<PsychTestViewModel> questionlist = new List<PsychTestViewModel>();
var datalistQuestions = db.Questions.ToList();
foreach (var question in datalistQuestions)
{
PsychTestViewModel ptvm = new PsychTestViewModel();
ptvm.QuestionID = question.QuestionID;
ptvm.Question = question.Question;
questionlist.Add(ptvm);
ViewBag.questionlist = questionlist;
var agree = from ans in db.Answers
where ans.Answer == 1 && ans.QuestionID == ptvm.QuestionID
select new { Answer = ans.Answer };
var somewhatAgree = from ans in db.Answers
where ans.Answer == 2 && ans.QuestionID == ptvm.QuestionID
select new { Answer = ans.Answer };
var disagree = from ans in db.Answers
where ans.Answer == 3 && ans.QuestionID == ptvm.QuestionID
select new { Answer = ans.Answer };
int Agree = agree.Count();
int SomewhatAgree = somewhatAgree.Count();
int Disagree = disagree.Count();
ViewBag.countSomewhatAgree = SomewhatAgree;
ViewBag.countAgree = Agree;
ViewBag.countDisagree = Disagree;
}
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
I have a JSON array:
var details = [
{
'address':'Pantaloons,701-704, 7th Floor, Skyline Icon Business Park, 86-92 Off A. K. Road,Marol Village, Andheri East,Mumbai, Maharashtra 400059',
'lat':'19.099910',
'lng':'72.915373',
'time':'NA',
'sex':'Unisex',
'place':'mall'
},
{
'address':'Garodia Shopping Centre,Ghatkopar East,Mumbai, Maharashtra 400077',
'lat':'19.074185',
'lng':'72.908169',
'time':'NA',
'sex':'Male',
'place':'mall'
},
{
'address':'EF Mall,Andheri,Rambaug, MHADA Colony 20, Powai,Mumbai, Maharashtra 400076',
'lat':'19.119056',
'lng':'72.901324',
'time':'NA',
'sex':'Male',
'place':'mall'
},
];
which also have dynamic variable details.['distance'].Here getDistance() is haversine formula.
var dist = getDistance(lt,lg,lat,lng);
details[i]['distance'] = dist;
All these values in list gets displayed in div for which I want to sort the list by distance.
for (i = 0; i < details.length; i++) {
var add= details[i].address;
var lat = details[i].lat;
var lng = details[i].lng;
var time = details[i].time;
var latLng = new google.maps.LatLng(lat, lng);
var Gender = details[i].sex;
var type = details[i].place;
var dist = getDistance(lt,lg,lat,lng);
details[i]['distance'] = dist;
document.getElementById('list').innerHTML +='<p><img src="'+type+'.png" style="float:left;margin-right:5;"><div id="address"> ' + add +'</div><br><img style="height:30;float:right;" src="'+Gender+'.png" title="+Gender+"><a class="review" href="#">See Reviews</a>'+'<img style="float:right;margin-top:6;" src="write.png" title="Write a Review"><div id="time">Timings:'+ time +'</div>'+details[i].distance +'km'+'</p><hr/>';
}
My implementation is as follows
details.sort(function(a,b) { return parseFloat(a.distance) - parseFloat(b.distance) } );
However this only sorts values by distance and displays the other values of lists as it is like address,type(i.e it shows distance of some other address to some another address after sorting).The whole set of array must get sort without having wrong details.
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
for(var i=0; i<objs.length; i++){
objs[i]['distance'] = objs[i]['last_nom'];
}
function compare(a,b) {
if (a.distance < b.distance)
return -1;
if (a.distance > b.distance)
return 1;
return 0;
}
objs.sort(compare);
alert(JSON.stringify(objs));
out put: [{"first_nom":"Pig","last_nom":"Bodine","distance":"Bodine"},{"first_nom":"Lazslo","last_nom":"Jamf","distance":"Jamf"},{"first_nom":"Pirate","last_nom":"Prentice","distance":"Prentice"}]
DEMO
It's a bit hard to answer your question since there is no distance property in your array as pointed out by birdspider. In any case, your method should work. You can test this in the console.
var details = [{'distance':'24.1','b':99},{'distance':'-12.5','b':100},{'distance':'35.6','b':101}]
details.sort(function(a,b) { return parseFloat(a.distance) - parseFloat(b.distance) } )
Now check the details variable again and you'll see:
[{'distance':'-12.5','b':100},{'distance':'24.1','b':99},{'distance':'35.6','b':101}]
Looking for some advice.
I am trying to create a dynamic table with knockout (it's great but I'm only on first steps of it).
This table works, but I still get some issues:
1. (update: deleted)
2. self.ave returns NaN, not an calculated average weight of selected risks;
self.ave = ko.computed(function () {
var total = 0;
for (var i = 0; i < self.risks().length; i++) {
total += self.risks()[i].weight;
}
return total/self.risks().length;
});
Update: It seems, that every time I add new Risk, the weight of it is 0. Also sum of all risks is calculated as 1 (weight of default risk) + 0(weight of any of new risk) + 0 +n...
update2: still looking for any help
http://jsfiddle.net/Skaidrius/52xdL/
there are some minor mistakes.
For first problem- availableRisks should not be common it should be attached with Activity.
var Activity = function (title) {
var self = this;
self.title = ko.observable(title);
self.availableRisks = ko.observableArray([{
name: "Low",
weight: 1
}, {
name: "Medium",
weight: 2
}, {
name: "High",
weight: 3
}]);
};
2- self.risks()[i].weight is observable so access it with parenthesis.
self.ave = ko.computed(function () {
var total = 0;
for (var i = 0; i < self.risks().length; i++) {
total += self.risks()[i].weight();
}
return total/self.risks().length || 0;
});
change binding in view for availableRisks
<!-- ko foreach:risks -->
<td>
<select class="form-control input-sm" data-bind="options: $parent.availableRisks, value: risks.weight, optionsText: 'name'"></select>
</td>
<!-- /ko -->
Fiddle Demo