Meteor how to access different documents in a form - javascript

I have a simple form that uses a couple different helpers :
<select class="form-control">
{{#each openTables}}
<option>Table {{tableNumber}}</option>
{{/each}}
</select>
<select id="working-servers" class="form-control">
{{#each workingServers}}
<option>{{name}}</option>
{{/each}}
</select>
<input id="num-of-guests-select" type="text" value="" name="num-of-guests-select">
openTables and workingServers are global helpers that access different collections
Template.registerHelper('openTables', () => {
let openTables = CurrentTables.find({occupied : false});
if(openTables) {
return openTables;
}
})
Template.registerHelper('workingServers', () => {
let servers = Servers.find({working : true});
if(servers) {
return servers;
}
});
My question is basically : I am trying to update a document in that CurrentTables collection with the information from the form.
Template.newTableModal.events({
'click #sendTable' : function(event, template) {
event.preventDefault();
event.stopPropagation();
}
});
In that event function, how do I access the data context of those select boxes? For example,
{{#each workingServers}}
<option>{{name}}</option>
{{/each}}
each of the objects in workingServers has an ID that I want to be able to access in that event function :
CurrentTables.update(tableId?, {$set: {"serverId" : ??, "currentGuests" : ??}});
How do I access those documents in relation to the document in the form when I make it? Rather, how do I get that serverId from the document selected in that workingServers loop.
Is there a better way to do this kind of thing because I need to be able to do similar forms in the future? I mean I know I could take the name value ,
$("#working-servers").val() and look up in the Servers collection to find the ID that matches but that seems really bad.

<select>
<option value="1">Volvo</option>
<option value="2">Saab</option>
<option value="3">Opel</option>
<option value="4">Audi</option>
</select>
value is the returned value when selected, the text part inside the tag is the displayed value.
So, use your id in value and that's what you'll get when selecting
{{#each workingServers}}
<option value={{serverId}}>{{name}}</option>
{{/each}}

Related

Dependent dropdown menu in different collection

I'm new in Meteor. I'm trying to make dropdown menu dependent in other dropdown. The first one for client name in Customers collection & the second for the client address in Addresses collection. I've 2 collections Customers & Addresses. This is my code but don't know what to do next.
EDIT: i put both templates in another template called new order
HTML:
<template name="selectClient">
Client Name :
<select class="select">
<option selected disabled>Choose client name</option>
{{#each custom}}
<option>{{clientName}}</option>
{{/each}}
</select>
</template>
<template name="selectAddress">
Address:
<select class="select" name="Choose the address">
<option selected disabled>Choose the address</option>
{{#each address}}
<option>{{addressName}}</option>
{{/each}}
</select>
</template>
main.js
Template.selectClient.helpers({
'custom': function(){
return Customers.find();
}
});
Template.selectAddress.helpers({
'address': function(){
return Addresses.find();
}
});
var clientName= $('[name="newName"]').val();
var mobNumber = $('[name="newMob"]').val();
var age = $('[name="age"]').val();
var radioValue= $('[name="gender"]').val();
Customers.insert({
clientName: clientName,
age: age,
radioValue:gender,
createdAt: new Date()
});
var addressName = $('[name="addressName"]').val();
var detail = $('[name= details]').val();
Addresses.insert({
addressName: addressName,
detail: detail,
createdAt: new Date()
});
Customers = new Mongo.Collection('customers');
Addresses = new Mongo.Collection('addresses');
Mobile = new Mongo.Collection('mobile');
Since you are using two templates in parallel (and not in a parent-child relation) you may use a ReactiveVar to cache the current selected client name:
const selectedCustomer = new ReactiveVar()
Note, that it needs to be accessible for both templates. Either you declare it with both templates in one file or your use import / export to provide access over many files.
Now your customers select needs to have a value assigned to each option, so we can cache it on selection change:
<template name="selectClient">
Client Name :
<select class="select-customer">
<option selected disabled>Choose client name</option>
{{#each custom}}
<option value="clientName" selected="{{#if selectedClient clientName}}selected{{/if}}">{{clientName}}</option>
{{/each}}
</select>
</template>
I renamed it's class, to prevent confusion in naming, to select-customter. Noticed the {{#if selectedClient}}... code? We will use a helper to restore the last selected state on the dropdown. Otherwise your dropdown selection will reset on the next rendering cycle:
Template.selectClient.helpers({
'custom': function(){
return Customers.find();
},
selectedClient(name) {
const selected = selectedCustomer.get()
return selected && selected.clientName === name
}
});
We get the selected customer from the cache and check if the current option's value is the same. If true we can flag the option as selected.
Now you still need an event that covers the selected client:
Template.selectClient.events({
'change .select'(event, templateInstance) {
// get the value using jQuery
const value = templateInstance.$(event.currentTarget).val()
// update the ReactiveVar
selectedCustomer.set({ clientName: value })
}
})
It saves the selected value (currently the clientName) in a query-able format. Now in your adresses you just need to query all Adresses documents using the cached selected client:
Template.selectAddress.helpers({
'address': function(){
const query = selectedCustomer.get() || {}
return Addresses.find(query);
}
});
If a client is selected it will server as the query, otherwise all adresses will be returned.
The good thing is, that this ReactiveVar already provides you the capability to trigger a new rendering cycle if it updates, since your helpers' code relies on it and Blaze automatically resolves this for you.
Modificatopns
This code assumes, that Adresses have a relation to Customers by a field named clientName. If you have stored the relation by using other fields, such as _id - clientId you need to modify your code accordingly.
You could also hide the second dropdown and only display it, if there is a value in selectedCustomer.

How to get value from DB to on-change event?

How to get value from DB to the on-change event? Here is the example
$("#widgetpanel").html(' >data="http://localhost:8080/guest?key='+$(this).val()+'item=??">');
I'm getting key from the drop-down using below method but I couldn't get the item value from the router. Please advise how to get third value from the router to append in URL string?
my requirement is getting data from DB to display in the drop-down and based on drop down value change the URL to display different items on the screen.
Below code which retrieves the value from DB using nodejs router.
router.get('/', function(req, res, next) {
c.query("SELECT w.title,w.key,w.item FROM widgets as w", function(err, rows, fields){
if(err) throw err;
//console.log(rows);
res.render('index', {
"widgets": rows
});
});
});
Below code which gets show the DB value into a dropdown(key, value). I can get the item value {{item}} on below screen but I don't want to here.
{{#if widgets}}
<select id="key">
<option value="">Select</option>
{{#each widgets}}
<option value="{{key}}">{{title}}</option>
{{/each}}
</select>
{{else}}
<p>No Projects</p>
{{/if}}
Below code which displaying an embedded screen based drop down value. I can utilize key, value to append URL to get the corresponding items but I need one more from DB to appended to URL string which is "Item".
$("#key").on('change',function(){
$("#widgetpanel").html('data="http://localhost:8080/guest?key='+$(this).val()+'item=??">');
});
You could use an extra attribute on the <option> tag to store your item. Your render code would look like:
<select id="key">
<option value="">Select</option>
{{#each widgets}}
<option value="{{key}}" data-item="{{item}}">{{title}}</option>
{{/each}}
</select>
And then your javascript could look like:
$('#key').on('change', function() {
var $o = $(this).children('option:selected');
$("#widgetpanel").html('data="http://localhost:8080/guest?key='+$o.attr('value')+'item='+$(o).attr('data-item')+'">');
});
Example:
$('#key').on('change', function() {
var $selectedOption = $(this).children('option:selected');
var selectedKey = $selectedOption.attr('value');
var selectedItem= $selectedOption.attr('data-item');
var url = "http://localhost:8080/guest?key="+selectedKey+"&item="+selectedItem;
$('#log').val(url);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="key">
<option value="">Select</option>
<option value="key1" data-item="item1">Title 1</option>
<option value="key2" data-item="item2">Title 2</option>
<option value="key3" data-item="item3">Title 3</option>
<option value="key4" data-item="item4">Title 4</option>
</select>
<input type="text" id="log" style="width:100%"/>

How to pass select list value in action link without using javascript and creating a model for it?

I have a shopping cart and I created a simple select list for quantity via Html. I would like to use an Html.ActionLink to get the value of that select list, however if I use JavaScript in will not work as it is inside a PartialView called product and there are multiple number of product on the page.
How could I get the value of that select list without JavaScript? I did look around, but did not find anything useful. Is there any other way?
PartialView
<p>#Model.Description</p>
<p id="price">#Model.Price</p>
<p class="id hidden">#Model.GadgetID</p>
<select name="Select" id="quantity">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<p>
Html.ActionLink("Add To Cart", "AddOrder", "Home",new { qty = ?? , id = Model.GadgetID, price = Model.Price }, null )
</p>
Or if I use JavaScript how can I get the right details as there are multiple products on the page.
View that includes that PartialView.
<div class="col-lg-10 products">
<div class="pad">
#foreach (var item in Model)
{
foreach (var gadget in item.Gadgets)
{
#Html.Partial("Gadget", gadget)
}
}
</div>
</div>
JQuery
<script type="text/javascript">
$(document).ready(function () {
$(".AddToCartBtn").click(function () {
var _qty = $(this).find("#quantity").val();
var _id = $(this).find(".id").val();
var _price = $("#price").html();
alert("qty: " + _qty + " id: " + _id + " price: " + _price);
});
});
You cannot do it without client side javascript because user can change the selection of your quantity dropdown at client side.
With Javascript / jQuery, you can read the value of selected option and append to the query string when the link is clicked. Also since you will have the same markup generated from the partial view, you should not use hardcoded static ids. Id's should be unique for html elements. With your current code, it will generate same id for all the quantity select elements. You can use a css class and use the closest() and find() method to get access to the quantity select element of the link clicked.
<div class="gadgetItem">
<select name="Select" class="qtySelect">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
#Html.ActionLink("Add To Cart", "AddOrder", "Home",
new { #id = Model.GadgetID, price = Model.Price }, new { id="addToCart"} )
</div>
and in JavaScript, listen to the click event on the link. Assuming jQuery is available to the page,(this code should go in the main page,not in the partial view)
$(function(){
$(document).on("click","#addtoCart",function(e){
e.preventDefault(); // Stop the normal link click behaviour
var currentUrl = $(this).attr("href"); // Get the url
// Append the quantity value to query string
var newUrl = currentUrl + "?qty =" + $(this).closest(".gadgetItem")
.find(".qtySelect").val();
window.location.href=newUrl; ///Load the new page with all query strings
});
});
Also I suggest you not read the price from the client request. You should always read it back from the db in server based on the Id of the item. If not, I can update the price in the query string to "0.0001" and order thousands of your products!

Ember simple array to display in component

Simple array in an component, that it will be display in a selector tag. I'm not being able to make it to work. The firstSelector doesn't display anything.
In the component.js:
sortPropertiesAsc: ['value:asc'],
selectors: ['model.modelObjects', 'model.location'],
firstSelector: function(){
const firstGroupObjects = this.get('selectors')[0];
return Ember.computed.sort(firstGroupObjects, 'sortPropertiesAsc');
}.property(),
In the component.hbs
<select onchange={{ action 'selectBrand' value="target.value" }}>
<option value="" >Select company</option>
{{#each firstSelector as |company|}}
<option value={{company.id}} selected={{eq brand company.id}}> {{company.value}}</option>
{{/each}}
</select>
if I write the firstSelector like this in the component.hbs, it will work:
firstSelector: Ember.computed.sort('model.modelObjects', 'sortPropertiesAsc'),
How can I write it like the other way(as a function)
I'm not sure all that's at play in your setup, but one thing I noticed off the bat was if you want your computed property to fire based on changes to selectors, you'd want something like this.
firstSelector: Ember.computed('selectors', function() {
const firstGroupObjects = this.get('selectors.firstObject');
return Ember.computed.sort(firstGroupObjects, 'sortPropertiesAsc');
})
If sortPropertiesAsc changes values you'd want to add it in too
firstSelector: Ember.computed('selectors', 'sortPropertiesAsc', function() {
const firstGroupObjects = this.get('selectors.firstObject');
return Ember.computed.sort(firstGroupObjects, 'sortPropertiesAsc');
})

Populate drop down list in Meteor

I am building a drop down list in Meteor using a helper function. However, users will need to be able to update the form in the future so I need the form to repopulate with all the previously selected values based on data in Mongo. I am able to populate textboxes and text areas in my form with my collection data but I have been unable to set the value in the drop down list to what is being stored in my Mongo collection.
The solution I have now is close, I think. It works if a user refreshes the page when viewing a specific record but navigating to the template using iron:router the helper function is called prior to the template being fully rendered, leaving the selected value in the drop down blank. If I move the logic to an OnRendered block, then I am unable to get to this.source to dynamically pick up the value from the collection.
Does anyone have any ideas on how I might be able to populate the selected value of a drop down list based on the value that is stored to the collection? Thanks in advance!
<template name="leadForm">
<form id="newLeadForm">
<select class="form-control" name= "leadSource" id="leadSource">
<option disabled="disabled" selected="selected">Please Select</option>
{{#each categories}}
<option value="{{this}}">{{this}}</option>
{{/each}}
</select>
{{setDropdownValue}}
</form>
</template>
Template.leadForm.helpers({
'categories': function(){
return ["Option1", "Option2", "Option3"]
},
'setDropdownValue': function(){
$('#leadSource').val(this.source);
}
});
You don't need to set the dropdown with DOM manipulation, just let the templates do it for you. When the DB query changes, meteor will rerender the template for you.
template:
<template name="leadForm">
<form id="newLeadForm">
<select class="form-control" id="leadSource">
<option disabled="disabled">Please Select</option>
{{#each categories}}
<option value="{{this.option}}" {{isSelected this.option}}>{{this.option}}</option>
{{/each}}
</select>
</form>
<br/>
<button id='addOption'>Add a new option to Drowdown</button>
</template>
js: (I'm using the anti:fake package to generate data - meteor add anti:fake)
Options = new Mongo.Collection("options");
Selected = new Mongo.Collection("selected");
if (Meteor.isClient) {
Template.leadForm.helpers({
'categories': function(){
return Options.find();
},
'isSelected': function(option){
var selected = Selected.findOne('SELECTED') ? Selected.findOne('SELECTED').selected : '';
return option === selected ? 'selected' : '';
},
});
Template.leadForm.events({
'click #addOption': function () {
Options.insert({option: Fake.sentence(3)});
},
'change #leadSource': function(event, template){
Selected.update('SELECTED', {selected: event.target.value});
}
})
}
if (Meteor.isServer) {
// code to run on server at startup
Meteor.startup(function () {
if(Selected.find().count() === 0)
Selected.insert({_id: 'SELECTED', selected: ''});
if(Options.find().count() === 0) {
Options.insert({option: Fake.sentence(3)});
Options.insert({option: Fake.sentence(3)});
Options.insert({option: Fake.sentence(3)});
Options.insert({option: Fake.sentence(3)});
Options.insert({option: Fake.sentence(3)});
}
});
}
meteorpad example

Categories