Meteor and Mongo DB - javascript

I have two questions.
1) I have these two document in MongoDB calender and calendarios_slaves. calender has a subdocument with array of calendarios_slaves ObjectID.
I have tried several queries but all to no result, How cxan I pull the ObjectID's of all the calendarios_slaves in the calender document.?
this is the calender document:
{
"_id" : ObjectId("577a09d3e9ac22d62a20ab01"),
"status_visualizacion" : "visible",
"status_tipo" : "Pintura",
"createdAt" : ISODate("2016-07-04T07:01:39.018Z"),
"usuarios_admin" : [
ObjectId("5773976c201bb491f499c180"),
ObjectId("577a03db9da98306f624c3d9"),
ObjectId("577a041d9da98306f624c3da"),
ObjectId("577a07b7e9ac22d62a20aae9"),
ObjectId("577a07c6e9ac22d62a20aaea"),
"Ys6fiychXcSfCgWox"
],
"grupo_usuarios" : [
ObjectId("5773976c201bb491f499c180"),
ObjectId("577a03db9da98306f624c3d9"),
ObjectId("577a041d9da98306f624c3da"),
ObjectId("577a07b7e9ac22d62a20aae9"),
ObjectId("577a07c6e9ac22d62a20aaea")
],
"calendario_slaves" : [
ObjectId("577b6a0114b9512e1e3f4c10"),
ObjectId("577b6a1d14b9512e1e3f4c11"),
ObjectId("577b6a2414b9512e1e3f4c12")
]
}
2) Is there anyway of pulling out nodes from a query in javascript in meteor. I used a queries to get all whole document in meteor (Client) javascript but couldn't get the nodes even though I was able to do that in the html using the #each loop..
Meteor.subscribe("calenders_user_visible");
Template.calendarios_visibles.helpers({
ls_calenderios_visibles: function(){
var result = Calender.find({status_visualizacion: "visible"});
return result;
}
});
<template name= "calendarios_visibles">
Calendarios visible!
<ul>
{{#each ls_calenderios_visibles}}
<li class = "calendarios_slave"> Calendarios slaves: {{calendario_slaves}} </li>
</ul>
{{/each }}
</template>
Result en Browser:
Calendarios visible!
Pintura visible
Calendarios slaves: ObjectID("577b6a0114b9512e1e3f4c10"),ObjectID("577b6a1d14b9512e1e3f4c11"),ObjectID("577b6a2414b9512e1e3f4c12")
vehiculo visible
Calendarios slaves: ObjectID("577b6a0114b9512e1e3f4c10"),ObjectID("577b6a1d14b9512e1e3f4c11"),ObjectID("577b6a2414b9512e1e3f4c12")
montaje visible
Calendarios slaves: ObjectID("577b6a0114b9512e1e3f4c10"),ObjectID("577b6a1d14b9512e1e3f4c11"),ObjectID("577b6a2414b9512e1e3f4c12")
Is there any way of getting these ObjectIds in Javascript immediately after getting the queries result?? I am only interested in these ObjectId values to make other queries not to display them in the browser.
Could any one with more experience help me out please?
Thanks

For 1st :
There are two way if you are want to get a result for single or more than one calender doc.
For single doc :
var calender = calenderCollection.findOne('ID');
var result= [];
if(calender.calendario_slaves.map){
result = calender.calendario_slaves.map(function(data){
return data;
})
}
return data;
For multiple doc :
var calenders = calenderCollection.find({query}).fetch();
var result= [];
for ( var i = 0; i < calenders.length; i++ ) {
for ( var j = 0; j < calenders[i].calendario_slaves; j++ ) {
result.push(calenders[i].calendario_slaves[j]);
}
}
return result;
For 2nd :
<ul>
{{#each ls_calenderios_visibles}}
{{#each calendario_slaves}}
<li class = "calendarios_slave">
Calendarios slaves: {{this}} // You can pass this into another helper to perform some operation.
</li>
{{/each}}
{{/each }}
</ul>
#note: your question 2 is not well clear for me, Please let me know if you need something else for question 2.

Related

ng-repeat not rendering data from array

I am working on a web app where non-profit organizations can create a profile and be easily searchable by various parameters. In the "create and organization" form, I have a nested array where the organization can add donations that they need. The array is storing ok (I can add multiple donations), however when I try to display it using ng-repeat, nothing renders. When I don't use the ng-repeat and just display via {{ ctrl.organization.donations }} the information shows up with brackets and quotation marks.
Here is the code that I use to add the donations (via the newOrganization controller):
function NewOrganizationController(OrganizationService, CategoryService, $stateParams, $state, $http, Auth){
var ctrl = this;
CategoryService.getCategories().then(function(resp) {
ctrl.categories = resp.data;
});
ctrl.donations = [{text: ''}];
Auth.currentUser().then(function(user) {
ctrl.user = user;
})
ctrl.addNewDonation = function() {
var newDonation = ctrl.donations.length+1;
ctrl.donations.push({text: ''});
};
ctrl.removeDonation = function() {
var lastItem = ctrl.donations.length-1;
ctrl.donations.splice(lastItem);
};
ctrl.addOrganization = function() {
var donations = this.donations;
var allDonations = [];
for (var key in donations) {
if (donations.hasOwnProperty(key)) {
var donation = donations[key].text;
allDonations.push(donation);
}
}
var data = {
name: ctrl.organization.name,
description: ctrl.organization.description,
address: ctrl.organization.address,
donations: allDonations.join("/r/n"),
category_id: this.category.id
};
OrganizationService.createOrganization(data);
$state.go('home.organizations');
};
}
angular
.module('app')
.controller('NewOrganizationController', NewOrganizationController);
Here is the code that I am using to display the array on my show page (this is what shows up with brackets, i.e. donations needed: ["food", "clothing"]):
<h5>{{ ctrl.organization.donations }}</h5>
This is the ng-repeat code that is not rendering anything to the page:
<li class="list-group-item" ng-repeat="donation in donations track by $index">
{{ donation }}
</li>
I've tried to use .join(', ') within the {{donation}} brackets, but this isn't recognized as a function.
edit: After taking AJ's suggestion here is a screenshot of what appears...anyone know how to fix this?
seems that my array is showing up in table form, with each row containing one character
Any help would be greatly appreciated. Here is a link to the github repo in case you want to look at anything else or get a bigger picture.
You need to use the same variable name that works in the h5
<li class="list-group-item" ng-repeat="donation in ctrl.organization.donations track by $index">
{{ donation }}
</li>

How to sort JSON data in ng-repeat?

I am getting a server response and binding these data to view using ng-repeat. Now I want to sort these data by priceList and name. I am able to sort name using orderBy, but not with priceList. I want to sort the products based on priceList. Sorting with name will change the order of list while sorting by priceList will effect only the order of products of each category. It will effect the order of displayed category. Please help me resolve this.
My code:
<div ng-controller="Ctrl">
<pre>Sorting predicate = {{predicate}};</pre>
<hr/>
<table class="friend">
<tr>
<th>Name
</th>
<th><a href="" ng-click="predicate = 'priceList'>price</a></th>
</tr>
</table>
<div ng-repeat="data in _JSON[0].categories | orderBy:predicate">
<div ng-repeat="vals in data.itemTypeResults |orderBy:'partTerminologyName'" id="{{vals.partTerminologyName}}">
`<h4 style="background-color: gray">{{vals.partTerminologyName}} : Position :{{vals.position}}</h4>`<br>
<div ng-repeat="val in vals.products">
<b> Quantity:{{val[0].perCarQty}}</b><br>
<b> part:{{val[0].partNo}}</b><br>
<b>sku:{{val[0].sku}}</b><br>
<b> qtyInStock:{{val[0].qtyInStock}}</b><br>
<b> priceList:{{val[0].priceList}}</b><br>
<b>priceSave:{{val[0].priceSave}}</b><br>
<b> qtyDC:{{val[0].qtyDC}}</b><br>
<b> qtyNetwork:{{val[0].qtyNetwork}}</b><br>
<b> priceCore:{{val[0].priceCore}}</b><br>
</div>
</div>
</div>
JS:
$scope._JSON = [
{"categories":
[
{"id":14061,"name":"Drive Belts",
"itemTypeResults":[
{"partTerminologyName":"Serp. Belt",
"position":"Main Drive",
"products":{
"5060635":[
{"perCarQty":2,"partNo":"5060635",
"sku":"20060904","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":19.15,"priceSave":3.29,
"priceCore":10.0}
],
"635K6":[
{"perCarQty":9,"partNo":"635K6",
"sku":"10062449","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":18.15,"priceSave":3.21,"priceCore":10.0}
]
}
}
]
},
{"id":2610,"name":"Drive Belt Tensioners, Idlers, Pulleys & Components",
"itemTypeResults":[
{"partTerminologyName":"Drive Belt Tensioner Assembly",
"position":"N/A",
"products":{
"950489A":[
{"perCarQty":4,"partNo":"950489A",
"sku":"10150833","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":18.15,"priceSave":3.21,"priceCore":10.0
}
]
}},
{"partTerminologyName":"Drive Belt Idler Pulley","position":"N/A",
"products":{
"89161":[
{"perCarQty":1,"partNo":"89161",
"sku":"99995959","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":17.15,"priceSave":3.21,"priceCore":10.0}
],
"951373A":[
{"perCarQty":2,"partNo":"951373A","pla":"LTN",
"plaName":"Litens",
"sku":"10150926","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":18.15,"priceSave":3.21,"priceCore":10.0}
]
}
}
]
}
]
}
];
$scope.predicate = '';
Fiddle: Fiddle
You might need to define a very good sorter function, or sort your products before they are interpreted by ng-repeat. I've created sorter function using underscore.js (or lodash).
You can checkout the demo (or the updated demo). Products are first sorted by category and then sorted by price in every category.
<!-- in html -->
<button ng-click="sortFn=sortByPrice">Sort By Price</button>
<button ng-click="sortFn=doNotSort">Do not Sort</button>
...
<div ng-repeat="val in sortFn(vals.products)">
...
// in js
$scope.sortByPrice = function(products) {
return _.sortBy(products, function(product) {
return product.length > 0 ? product[0].priceList : 0;
});
};
$scope.doNotSort = function(products) {
return products;
};
$scope.sortFn = $scope.doNotSort; // do not sort by default
BTW: You are directly calling val[0], which is very dangerous, if the product does not contain any elements, your code will break. My code won't ;-)
Update 1
The author asks me for a more pure Angular way solution.
Here is my answer: I think my solution is exactly in Angular way. Usually you can implement a filter (similar to orderBy) which wraps my sortByPrice. Why I don't do that, because you have ng-click to switch your order filter. I'd rather put control logic into a controller, not as pieces into view. This will be harder to maintain, when your project keeps growing.
Update 2
Okay, to make the +50 worthy, here is the filter version you want, (typed with my brain compiler) Please check in fiddle
You need to organize the products in other estructure. For example:
$.each($scope._JSON[0].categories , function( i , e) {
$.each(e.itemTypeResults, function(sub_i,sub_e) {
$.each(sub_e.products, function(itemTypeResults_i,product) {
console.log(product);
var aProduct = new Object();
aProduct.priceList = product[0].priceList;
aProduct.name = e.name;
$scope.products.push(aProduct);
});
} )
});
The code is not very friendly but what i do is putt all the products in one array so they can be ordered by the price. You have the products inside categories so that's why angular is ordering by the price in each category.
Fiddle:
http://jsfiddle.net/7rL8fof6/1/
Hope it helps.
Your fiddle updated: http://jsfiddle.net/k5fkocby/2/
Basically:
1. Digested the complex json object into a flat list of objects:
var productsToShow = [];
for (var i=0; i < json[0].categories.length; i++){
var category = json[0].categories[i];
for (var j=0; j<category.itemTypeResults.length;j++){
var item = category.itemTypeResults[j];
var products = item.products;
for (var productIndex in products) {
var productItems = products[productIndex];
for (var k=0; k<productItems.length;k++){
var productItem = productItems[k];
// Additions:
productItem.categoryName = category.name;
productItem.partTerminologyName = item.partTerminologyName;
productItem.position = item.position;
productsToShow.push(productItem);
}
}
}
}
Show category title only when needed by:
ng-repeat="product in (sortedProducts = (productsToShow | orderBy:predicate))"
and
ng-show="sortedProducts[$index - 1].partTerminologyName != product.partTerminologyName"
you can sort from your database and get final JSON data..
db.categories.aggregate([{$group : {category : {your condition} }, price: {$sort : { price: 1 } },}}])

Protractor AngularJS count, copy, and verify a list span

I am new to automated testing, Protractor, and angularJS. I have a list that I would like to count, copy to an array maybe, and verify the list text is present. For example The list shows Attractions, Capacity, and Content to the user so they know what privileges they have.
Below is the .html
<div class="home-info">
<div class="home-top home-section">
<h3>User Information</h3>
<div class="home-box">
<div class="property-group wide">
<span>
Change Phillips<br />
</span>
</div>
</div>
<div class="home-box">
<div class="property-group wide">
<div>Editors:</div>
<span>
<ul class="property-stack">
<li><span>Attractions</span>
</li>
<li><span>Capacity</span>
</li>
<li><span>Content</span>
</li>
<li><span>Media</span>
</li>
<li><span>Options</span>
</li>
<li></li>
<li></li>
<li><span>Upload CADs</span>
</li>
</ul>
</span>
</div>
</div>
</div>
Below is the code I have written. I can get the first item on the list however using .all isn't working for me.
var text = "";
browser.driver.findElement.all(By.xpath("//li/span")).count().then(function(count) {
initialCount = count;
console.log(initialCount);
});
browser.driver.findElement(By.xpath("//li/span")).getText().then(function(text) {
console.log(text);
});
I'm trying to avoid using xpath as I was told to try and avoid. To be honest Im lost. Thanks for the help in advance.
Code used for matching:
expect(myLists).toEqual(['Attractions', 'Capacity', 'Conent',
'Media', 'Options', 'Upload CADs'
]);
I am not sure what version of protractor you're using but you should be able to just call element without the browser or driver prefix. Using element.all should get you the array of of elements you're looking for.
If you want to access specific indexes within that array you can use the .get(index) suffix to the element.all
So below:
1. you get the array of the elements
2. you get the count of the array
3. we call a for loop to iterate through all the indexes of the array
4. each index of the array we call the getText() and print it to the console
var j = 0; // using this since the i iterator in the for loop doesn't work within a then function
var textList = [];
var text = "";
var myLists = element.all(by.css("li span"));
myLists.count().then(function(count) {
console.log(count);
for(int i = 0; i < count; i++){
myLists.get(i).getText().then(function(text) {
textList[j++] = text;
console.log(text);
});
}
});
EDIT:
In researching I actually found another way to iterate through the array of elements by using the .each() suffix to the element.all.
var j = 0; // using this since the i iterator in the for loop doesn't work within a then function
var textList = [];
var text = "";
var myLists = element.all(by.css("li span"));
myLists.count().then(function(count) {
console.log(count);
myLists.each(function(element, index) {
element.getText().then(function (text) {
textList[j++] = text;
console.log(index, text);
});
});
});
you should be able to use the textList array to match things.
expect(textList).toEqual(['Attractions', 'Capacity', 'Conent',
'Media', 'Options', 'Upload CADs'
]);

$scope.apply not working in Angular

im trying to learn Angular.
Here is what im trying to do:
I am building an App that shows me citys. When i click on a city i want to see a list of all my favourite citys.
Using an "Show-List" Button with ng-click works but requires the button the be pushed.
Here is my approach for getting it done automatic:
I want a list in my DOM automatically updated on change of the list.
$scope.$watch('updatedList', function() {
// CHECK IF WORKS
console.log($scope.updatedList);
// APPLY TO DOM
$timeout(function(){
$scope.$apply(function () {
$scope.watchList = $scope.updatedList;
});
}, 1000)
});
The Console shows no error and gives out the correc values:
Object {city.3: "Herat", city.7: "Haag", city.10: "Tilburg" ......}
In my div is the following:
<ul>
<li ng-repeat="y in updatedList">{{ y }}</li>
</ul>
<ul>
<li ng-repeat="a in watchList">{{ a }}</li>
</ul>
First for the NG-Click-Version(which works on click) second for the $scope.$watch
Sorry for lots of questions but im really struggling with the Angular-Docs.
EDIT:
Function that Adds Citys to the List:
$scope.addToList = function(name,id) {
var cityToAdd = name;
var cityToAddID = id;
// ADD A CITY TO THE COOKIE -> WORKS
$cookies.put('city.' + cityToAddID, cityToAdd);
$scope.newList = $cookies.getAll();
$scope.addToListMessage = cityToAdd + " wurde hinzugefĆ¼gt";
// Show short INFONOTICE
window.setTimeout(function() {
$scope.$apply(function() {
$scope.addToListMessage = "";
});
}, 1000);
// Update the List
$scope.updateList();
};
Second Functions -> gets Values from Cookies and puts them to an Array:
$scope.updateList = function() {
var allCitys = $cookies.getAll();
// PUT ALL INTO AN ARRAY -> WORKS
var favouritesFromCookie = [];
$.each(allCitys, function(index, value) {
if (index.indexOf('city.') == 0) { favouritesFromCookie.push(value) }
});
// PUT THE ARRAY OF CITYS INTO A SCOPE_VARIABLE
$scope.updatedList = favouritesFromCookie;
};
Your $scope.updatedList needs to be an array to be used in ng-repeat.
You shouldn't directly write a list in expression. Try this
<ul>
<li ng-repeat="y in watchList">{{ y.city }}</li>
<li ng-repeat="y in watchList">{{ y.yourListItem}}</li>
</ul>

How to implement multiple filters on model's array/content via checkbox

I am trying to implement multiple filters on the same model. The attributes I want to apply the filter are arrays.
//Exam Model
App.Exam = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
courses : DS.hasMany('course',{ async: true }),
});
//Course Model
App.Course = DS.Model.extend({
name: DS.attr('string'),
description:DS.attr('string'),
professors: DS.attr(),
subjects: DS.attr(),
languages: DS.attr(),
exam: DS.belongsTo('exam', { async: true })
});
In the ExamsExam route after the model is resloved I extract the data I want to apply the filter on.
App.ExamsExamRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('exam', params.exam_id).then(function (exam) {
console.log("found single exam", exam);
return exam;
});
},
afterModel: function(model, transition){
var self = this;
var professorList = [];
var subjectList = [];
var languageList = [];
var promise = new Ember.RSVP.Promise(function(resolve, reject){
var courses = model.get('courses');
courses.forEach(function(course){
self.store.find('course', course.get('id')).then(function(course){
var profs = course.get('professors');
var subjects = course.get('subjects');
var languages = course.get('languages');
profs.forEach(function(prof) {
if (professorList.indexOf(prof) === -1) {
professorList.pushObject(prof);
}
});
subjects.forEach(function(subject) {
if (subjectList.indexOf(subject) === -1) {
subjectList.pushObject(subject);
}
});
languages.forEach(function(language) {
if (languageList.indexOf(language) === -1) {
languageList.pushObject(language);
}
});
});
});
var data = {
professorList: professorList,
subjectList: subjectList,
languageList: languageList
};
resolve(data);
});
promise.then(function(data) {
console.log(data);
model.set('professorNameList', data.professorList);
model.set('subjectList', data.subjectList);
model.set('languageList', data.languageList);
});
}
});
And this is my template
<script type="text/x-handlebars" data-template-name="exams/exam">
<h2>Exam page</h2>
<div class="row">
<div class="col-md-3 well">
<ul class="list-group well">
{{#each course in model.languageList}}
<li class="">
<label>
{{input type='checkbox'}}
{{course}}
</label>
</li>
{{/each}}
</ul>
<ul class="list-group well">
{{#each prof in model.professorNameList}}
<li class="">
<label>
{{input type='checkbox'}}
{{prof}}
</label>
</li>
{{/each}}
</ul>
<ul class="list-group well">
{{#each subject in model.subjectList}}
<li class="">
<label>
{{input type='checkbox'}}
{{subject}}
</label>
</li>
{{/each}}
</ul>
</div>
<div class="col-md-9">
{{#each course in model.courses}}
<div class="well">
Course name - {{course.name}}<br>
Professors - {{course.professors}}<br>
Subjects - {{course.subjects}}
</div>
{{/each}}
</div>
</div>
</script>
Now how do I change the content of the model so that if a user selects the language filter, only the courses belong to that selected language must be displayed.
Plus if the user selects language and subjects filter, only the filters matching that criteria should be displayed.
There is very little documentation on filtering via checkbox in ember.
Someone please suggest/guide me on how to approach this problem and get a clean solution.
Here is the JS BIN DEMO for better illustration of what I want to achieve.
Building on #joostdevries's answer...
Using every() with a callback is a fine solution, but it "feels" a little complicated. What you are looking for is basically an intersect between the arrays. For example, common professors to both an array of selected professors and array of professors in the model. Ember provides just such function, called ... wait for it ... intersection (see here) :). It returns an array containing the elements common to both arrays or an empty (0 length) array if there are no common elements.
Here is the same filteredCourses property, using the intersection method.
filteredCourses: function() {
var selectedProfessors = this.get('selectedProfessors'),
selectedLanguages = this.get('selectedLanguages'),
selectedSubjects = this.get('selectedSubjects'),
courses = this.get('model.courses');
var intersectFn = Ember.EnumerableUtils.intersection;
return courses.filter(function(course) {
return intersectFn(course.get('professors') || [], selectedProfessors).length ||
intersectFn(course.get('languages') || [], selectedLanguages).length ||
intersectFn(course.get('subjects') || [], selectedSubjects).length;
});
}.property('selectedProfessors.length', 'selectedLanguages.length', 'selectedSubjects.length')
First, we alias the intersection function as follows:
var intersectFn = Ember.EnumerableUtils.intersection;
This step is purely cosmetic - I just don't feel like typing Ember.EnumerableUtils.intersection every time; instead I just want to type intersectFn. Then, I just use the function to see if the arrays intersect. If they do - the length of resulting array would be greater than 0, which evaluates to true; otherwise - the length is 0, which evaluates to false. The one last quirk in all of this is that sometimes the property will be undefined which messes up the intersection method. For such cases, I set the array to empty.
So, course.get('professors') || [] means, if professors property (array) is defined - use it; otherwise - use an empty array.
Working solution here
With store.filter, you have a callback function which returns a boolean that decides whether or not something matches the filter:
filteredCourses: function() {
return courses.filter(function(course) {
return selectedProfessors.every(function(prof) {
return course.get('professors').contains(prof);
}) && selectedLanguages.every(function(lang) {
return course.get('languages').contains(lang);
}) && selectedSubjects.every(function(subj) {
return course.get('subjects').contains(subj);
});
});
}.property()
Here's an updated JSBin: http://emberjs.jsbin.com/comosepuno/1/. The checkbox component is borrowed from https://github.com/RSSchermer/ember-multiselect-checkboxes

Categories

Resources