Populate dropdown based on logged in user created records - mongodb

How do I populate a dropdown with records/documents created by the logged in user? I have a collection that many users can create schools. I want it to be that if a user that have created more than a school the dropdown should show populated with the number of schools. If it is only one, the _id of the school should just be passed to a hidden field.
This is the school collection:
if (Meteor.isServer) {
Meteor.methods({
SchoolRegister: function (newschoolname, newschoolmotto, newschholvision, sellschool, schooltype,
schoolfeerange, schoolcurriculum) {
if (!Meteor.userId()) {
throw new Meteor.Error('Not authorized', 'You must be logged in to add a new school!');
return false;
}else{
var regUsername = Meteor.user().username;
var year = new Date().getFullYear();
var month = new Date().getMonth() + 1;
var day = new Date().getDate();
var date = (month +"/" +day +"/" +year).toString();
var schoolId = NewSchoolDB.insert({
newschoolnamevar: newschoolname,
newschoolmottovar: newschoolmotto,
newschholvisionvar: newschholvision,
sellschoolvar: sellschool,
schooltypevar: schooltype,
schoolfeerangevar: schoolfeerange,
schoolcurriculumvar: schoolcurriculum,
createdAt: new Date(),
author: regUsername,
authorId: Meteor.userId()
});
return schoolId;
}
},
UserRecords: function () {
if (!Meteor.userId()) {
throw new Meteor.Error('Not authorized', 'You must be logged in to add a new school!');
return false;
}else{
//var UserDocuments = NewSchoolDB.find({authorId: Meteor.userId()}).count();
return NewSchoolDB.find({authorId: Meteor.userId()});
}
}
});
}
I'm using this to call the method:
Template.SchoolContactLayout.helpers({
UsersDocuments: function () {
return Meteor.call('UserRecords');
console.log(Meteor.call('UserRecords'));
}
});
This is the template file
{{# if UsersDocuments == 1 }}
<input type="hidden" name="schoolId" value="{{ UsersDocuments._id }}">
{{else}}
<div class="form-group">
<select class="form-control" name="schoolnames" id="schoolnames" required style="color: black; width: 100%; font-family: 'candara'">
<option value="{{UsersDocuments._id}}">{{UsersDocuments.newschoolnamevar}}</option>
</select>
</div>
{{/if}}
All in all, no error was returned and it did not work.

Meteor.call('UserRecords') is Async function you have to wait for it in a callback and use session instead.
Meteor.call('UserRecords', function(err,res){
// res will be your return value you can set your session here
});
or you can use package for example you can search atmosphere for reactive method

Related

How can I send a single string value through View Form in my webAPI?

How can I send a single string value through view from in the WebAPI made in ASP.NET core.
Here is my API:
[HttpPost]
[Route("studentlogin/{value}")]
public IActionResult StudentLogin(string value)
{
string name = String.Concat(value.Where(s => !Char.IsWhiteSpace(s)));
name = name.ToLower();
var newStudent = new Student();
newStudent.FullName = name;
db.Entry(newStudent).State = EntityState.Added;
db.SaveChanges();
var selectStudent = db.Students.Where(ss => ss.FullName == name).FirstOrDefault();
var id = selectStudent.Id;
string idToString = id.ToString();
string answer = sha384converter(idToString);
selectStudent.HashId = answer;
db.Entry(selectStudent).State = EntityState.Modified;
db.SaveChanges();
return Ok();
}
I want to send paramenter value in it through View Forms, How can I send data in it?
Thanks in advance.
[Route("studentlogin/{value}")]
If you are using the above route, the request URL should like this: https://localhost:44310/api/apicontrollername/studentlogin/XXX, the parameter will be transferred from the URL and route.
to send paramenter value in it through View Forms, How can I send data
in it?
To send parameter value from posted form fields, you could modify the code as below:
In the API controller, remote the route parameter and add the FromForm attribute.
[HttpPost]
[Route("studentlogin")]
public IActionResult StudentLogin([FromForm]string value)
{
string name = "Default value";
if (!string.IsNullOrEmpty(value))
{
name = String.Concat(value.Where(s => !Char.IsWhiteSpace(s)));
}
... // add your code
return Ok(name);
}
Then, create a model which contain the value property, like this:
public class StudentLoginViewModel
{
public string value { get; set; }
}
In the View page, display the above model in the form:
#model WebApplication6.Models.StudentLoginViewModel;
<form id="myform">
<div class="form-group">
<label asp-for="value" class="control-label"></label>
<input asp-for="value" class="form-control" />
<span asp-validation-for="value" class="text-danger"></span>
</div>
<div class="form-group">
<input type="button" id="btnsubmit" value="Submit" class="btn btn-primary" />
</div>
</form>
and add the following script at the end of the above view page:
#section Scripts{
<script>
$(function () {
$("#btnsubmit").click(function () {
//use the serialize() method to encode a set of form elements as a string for submission
var data = $("#myform").serialize();
//you can also create JavaScript object and send the data.
//var data = { value: $("#value").val() };
$.ajax({
url: '/api/todo/studentlogin', // change the url to yours.
type: "post",
contentType: 'application/x-www-form-urlencoded',
data: data,
success: function (result) {
console.log(result);
}
});
});
})
</script>
}
The result as below:

Autocomplete for Two <Input>

I get a code from Google to autocomplete address fields. It works well for one "Input type=text". I use it for "Departure"
Problem is when i duplicate these code to have a second "Input type=text" as "Arrival" : it only works for one of them.
I Tried to change input id="autocomparr" and some var without success.
Regards
<input id="autocompdep"
placeholder="Enter your address"
onFocus="geolocate()"
type="text"/>
<script>
var placeSearch, autocomplete;
var componentForm = {
street_number: 'short_name',
route: 'long_name',
locality: 'long_name',
administrative_area_level_1: 'short_name',
country: 'long_name',
postal_code: 'short_name'
};
var options = {
componentRestrictions: {country: 'fr'}
};
function initAutocomplete() {
// Create the autocomplete object, restricting the search predictions to
// geographical location types.
autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autocompdep'), options, {types: ['geocode']});
// Avoid paying for data that you don't need by restricting the set of
// place fields that are returned to just the address components.
autocomplete.setFields(['address_component']);
// When the user selects an address from the drop-down, populate the
// address fields in the form.
autocomplete.addListener('place_changed', fillInAddress);
}
function fillInAddress() {
// Get the place details from the autocomplete object.
var place = autocomplete.getPlace();
for (var component in componentForm) {
document.getElementById(component).value = '';
document.getElementById(component).disabled = false;
}
// Get each component of the address from the place details,
// and then fill-in the corresponding field on the form.
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType).value = val;
}
}
}
// Bias the autocomplete object to the user's geographical location,
// as supplied by the browser's 'navigator.geolocation' object.
function geolocate() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var geolocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
var circle = new google.maps.Circle(
{center: geolocation, radius: position.coords.accuracy});
autocomplete.setBounds(circle.getBounds());
});
}
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=***&libraries=places&callback=initAutocomplete"
async defer></script>````
Answer to myself (and for others that will have this problem)
It is now working for 2 input text field on the same page. Geolococate is set for France and French Riviera to be more accurate for my needs.
Regards
<html>
<head>
<script src="https://maps.googleapis.com/maps/api/js?key=****&sensor=true&libraries=places"></script>
</head>
<body>
<label for="locationTextField1">Departure</label>
<input id="locationTextField1" type="text" size="50" >
<script>
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(43.093595, 6.153839),
new google.maps.LatLng(43.467646, 6.237595));
var options = {
bounds: defaultBounds,
componentRestrictions: {country: 'fr'}
};
function initDep() {
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById('locationTextField1'), options, {types: ['geocode']});
}
google.maps.event.addDomListener(window, 'load', initDep);
</script>
<br />
<br />
<label for="locationTextField2">Arrival</label>
<input id="locationTextField2" type="text" size="50">
<script>
function initArr() {
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById('locationTextField2'), options, {types: ['geocode']});
}
google.maps.event.addDomListener(window, 'load', initArr);
</script>
<script>
</script>
</body>
</html>

updating text using knockout computed function

In a table I have a checkbox bound to a bool in an observable array.
If any of the checkboxes in the table are checked / unchecked I want to update some text with the total checked.
I cannot get the computed function to fire, I have tried using ko.utils.unwrapObservable on both the array and location.isSelected in the 'if' statement below, am I just using it in the wrong place?
<input type="checkbox" data-bind="checked: isSelected"/>
<span class="text-left h5 ">Total Selected:</span><span data-bind="text: totalSelected" />
self.totalSelected = ko.computed(function () {
var selected = 0;
ko.utils.arrayForEach(self.SelectedLocations(), function (location) {
if (location.isSelected == true) {
selected = (+selected) + 1;
}
});
return selected;
}, self).extend({ notify: 'always' });
One of the issues is that isSelected is treated like a variable inside the computed: location.isSelected == true. However, if you intend to bind a checkbox to it, it must be an observable.
So, I have declared a function to create the children of self.SelectedLocations as:
var locationObservable = function() {
var self = this;
self.isSelected = ko.observable(false);
};
Then, you could change the counting in the computed variable as follows:
if (loc.isSelected()) {
selected++;
}
var locationObservable = function(selected) {
var self = this;
self.isSelected = ko.observable(selected);
};
var model = function() {
var self = this;
self.SelectedLocations = ko.observableArray();
self.SelectedLocations.push(new locationObservable(false)); // Set the state of the checkbox here.
self.SelectedLocations.push(new locationObservable(true));
self.SelectedLocations.push(new locationObservable(false));
self.totalSelected = ko.computed(function() {
var selected = 0;
ko.utils.arrayForEach(self.SelectedLocations(), function(loc) {
if (loc.isSelected()) {
selected++;
}
});
return selected;
}, self);
};
var vm = new model();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: SelectedLocations">
<input type="checkbox" data-bind="checked: isSelected" />
</div>
<span class="text-left h5 ">Total Selected:</span><span data-bind="text: totalSelected" />

Setting state in react. Is there a better way to write this without warning errors?

I am working on a registration form on react. I am a bit stuck with the validation part of it.
As of now I am getting the following warnings four times on the console: "warning Do not mutate state directly. Use setState() react/no-direct-mutation-state."
I am guessing the reason I am getting these errors is because of statements like these "this.state.errors.firstName = "First name must be at least 2 characters.";" and like this"this.state.errors = {};" in my code.
However, I do not know how to make this better and eliminate the warnings. If you can provide a better way for me to do this that would be awesome. Any help will be highly appreciated. Thanks so much in advance!
import React, { Component } from 'react';
import {withRouter} from "react-router-dom";
import HeaderPage from './HeaderPage';
import Logo from './Logo';
import RegistrationForm from './RegistrationForm';
import axios from 'axios';
class Registration extends Component {
mixins: [
Router.Navigation
];
constructor(props) {
super(props);
this.state = {
firstName:'',
lastName:'',
email:'',
errors:{},
helpText: '',
helpUrl: '',
nextLink:''
};
this.setUserState = this.setUserState.bind(this);
this.registrationFormIsValid = this.registrationFormIsValid.bind(this);
this.saveUser = this.saveUser.bind(this);
}
setUserState(e){
const target = e.target;
const value = target.value;
const name = target.name;
this.setState({[name]: value});
//delete this line
console.log(this.state[name]);
}
registrationFormIsValid(){
var formIsValid = true;
this.state.errors = {};
//validate first name
if(this.state.firstName.length < 2){
this.state.errors.firstName = "First name must be at least 2 characters.";
formIsValid = false;
}
//validate last name
if(this.state.lastName.length < 2){
this.state.errors.lastName = "Last name must be at least 2 characters.";
formIsValid = false;
}
//validate email
if(this.state.email.length < 2){
this.state.errors.email = "Email must be at least 2 characters.";
formIsValid = false;
}
this.setState({errors : this.state.errors});
return formIsValid;
}
saveUser(e, { history }){
e.preventDefault();
// const errorWrappers = document.getElementsByClassName('input');
// for (var i=0; i < errorWrappers.length; i++) {
// const isError= errorWrappers[i].innerHTML;
// if (isError.length > 0){
// errorWrappers[i].previousSibling.className = "error-input"
// }
// }
if(!this.registrationFormIsValid()){
return;
}
const values = {
firstName: this.state.firstName,
lastName: this.state.lastName,
email: this.state.email,
password: this.state.password,
phone: this.state.phone,
address: this.state.address,
dob: this.state.birthday
}
if (this.props.userRole === 'instructor'){
axios.post(`/instructors`, values)
.then((response)=> {
//delete this line
console.log(response);
})
.catch((error) => {
console.log(error + 'something went wrooooong');
});
this.props.history.push("/success-instructor");
}else{
axios.post(`/students`, values)
.then((response)=> {
//delete this line
console.log(response);
})
.catch((error) => {
console.log(error + 'something went wrooooong');
});
if (this.props.parent === "false"){
this.props.history.push("/success-student");
}else{
this.props.history.push("/success-parent");
}
}
}
//end of validation
render() {
return (
<div className="Registration">
<div className="container menu buttons">
<HeaderPage/>
</div>
<div className="page container narrow">
<div className="cover-content">
<Logo/>
<div className="container">
<h2 className="page-title">{this.props.title}</h2>
<a className="helpLink" href={this.props.helpUrl}>{this.props.helpText}</a>
<div className="main-content background-white">
<RegistrationForm
userRole={this.props.userRole}
onChange={this.setUserState}
onSave={this.saveUser}
errors={this.state.errors}
/>
<br/>
<br/>
<br/>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Registration);
Instead of
this.state.errors = {};
and
this.state.errors.lastName = "Last name must be at least 2 characters.";
use
this.setState({errors = {}});
this.setState({ errors: { lastName: "Last name must be at least 2 characters." } });
You need to avoid directly mutating the state.
The Warning itself answers the question. Please read the React Doc
carefully.
"warning Do not mutate state directly. Use setState()
react/no-direct-mutation-state."
Do not mutate state
Don't ever have code that directly changes state. Instead, create new object and change it. After you are done with changes update state with setState.
Instead of:
this.state.errors.someError1="e1";
this.state.errors.someError2="e2";
do this:
this.errorsObject=Object.assign({},this.state.errors,{someError1:"e1",someError2:"e2"};
and in the end:
this.setState({
errors:this.errorsObject
});
Object.assign lets us merge one object's properties into another one, replacing values of properties with matching names. We can use this to copy an object's values without altering the existing one.

Meteor Multi Input Mail

I have a problem for my form.
In my template contact , i want of this message insert on my (admin) page.
This code :
if(Meteor.isClient) {
Template.contact.events({
'submit #mymess' : function(){
event.preventDefault();
var nom = event.target.text.value;
var prenom = event.target.text.value;
var objet = event.target.text.value;
var mail = event.target.text.value;
var content = event.target.text.value;
if(nom != ''){
Messages.insert({
text: nom,
createdAt: new Date()
});
console.log('hello');
event.target.text.value = '';
}
if(prenom != ''){
Messages.insert({
text: prenom,
createdAt: new Date()
});
event.target.text.value = '';
}
if(objet != ''){
Messages.insert({
text: objet,
createdAt: new Date()
});
event.target.text.value = '';
}
if(mail != ''){
Messages.insert({
text: mail,
createdAt: new Date()
});
event.target.text.value = '';
}
if(content != ''){
Messages.insert({
text: content,
createdAt: new Date()
});
event.target.text.value = '';
}
},
});
}
<template name="contact">
<form id="mymess">
<div class="form-group">
<input type="text" name="prenom" class="input_mail_name " placeholder="Prénom">
<input type="text" name="nom" class="input_mail_name f_r" placeholder="Nom">
<input type="text" name="mail" class="input_mail_name long margin-top_20" placeholder="Email">
<input type="text" name="objet" class="input_mail_name margin-top_20 f_r" placeholder="Objet">
<textarea type="text" name="content" placeholder="Messages" class="input_txt_contact margin-top_20"></textarea>
<button type="submit" class="input_mail_send margin-top_20" id="submit">ENVOYER</button>
</div>
</form>
</template>
I don't understand why my form doesn't insert on my collection Messages
And in : lib/router/collection.js
Messages = new Mongo.Collection("messages");
You forgot to add the argument 'event' to your event handler. After you've added this argument, you can access your form elements by using event.target.[name].value.
It would be cleaner to add one object for each submit.
if(Meteor.isClient) {
Template.contact.events({
'submit #mymess' : function(event){
event.preventDefault();
var nom = event.target.nom.value;
var prenom = event.target.prenom.value;
var objet = event.target.objet.value;
var mail = event.target.mail.value;
var content = event.target.content.value;
if(nom != '' && prenom !='' && objet!='' && mail!='' && content !=''){
Messages.insert({
nom: nom,
prenom: prenom,
objet: objet,
mail: mail,
content: content,
createdAt: new Date()
});
console.log('hello');
event.target.nom.value = '';
event.target.prenom.value = '';
event.target.objet.value = '';
event.target.mail.value = '';
event.target.content.value = '';
}
}
});
}
You need to pass in the event object as a parameter to your function:
if(Meteor.isClient) {
Template.contact.events({
'submit #mymess' : function( event ){
event.preventDefault();
var nom = event.target.text.value;
var prenom = event.target.text.value;