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
Related
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.
I'm new from Meteor, and I need to realize a little dropdown menu and a search with the selected data in the dropdown menu.
I have devices.html :
<div class="ha_panel-selections">
<form id="plane-form">
<select id="plane-select">
<option disabled="disabled" selected="selected">Please Select</option>
{{#each plane}}
<option id="plane_selected" value="{{this}}">{{this.planeid}}</option>
{{/each}}
</select>
</form>
</div>
the data comes from the database: devices.js is:
Template.devices.helpers({
plane: function() {
return plane.find({});
}
});
Now what I want to do is take the selected value in the dropdown menu (the plane.planeid value), search in the db for that value, and print the data associated:
so for example, if I select "plane1" I can see planeid, flighttime, pilotname, ecc; if I change from "plane1" to "plane2" the data will change accordingly.
How can I pass the plane_selected value from html to devices.js? and back, once i will find the data in the db, how can I print the results passing the data form devices.js to devices.html ?
I think it should be (in devices.js) something like
Template.devices.events({
"change #plane-form": function (event, template) {
//console.log("event: " + util.inspect(event) );
//console.log("template: " + util.inspect(template) );
var selected = Session.get("plane_selected");
console.log("selected: " + selected);
}
});
What I'm doing wrong?
Taking into account that you're able to select the planeid, you're pub/sub seems to be working. All you need is another helper that give you back the rest of the plane's data.
devices.js
Template.devices.events({
"change #plane-select": function (event, template) {
var selected = event.target.value;
console.log("selected: " + selected);
Session.set("selectedPlane", selected);
}
});
Template.devices.helpers({
plane: function() {
return plane.find({});
},
planeData: function() {
return planes.findOne({
planeId: Session.get("selectedPlane")
});
}
});
devices.html
<p>
planeID: {{planeData.planeid}}
planeName: {{planeData.planeName}}
...
...
</p>
Note: It's up to you to use Session or reactive vars Session variables are lost on page refresh.
I have this code. I'm working in Blade template by Laravel framework.
<select class="form-control" name="id_zupanije" id="id_zupanije" onchange="popuniGradove(this, document.getElementById('id_grada'))">
#foreach($zupanije as $zupanija)
#if($zupanija->id == $idzupanije)
<option value="{{$zupanija->id}}" selected="selected">{{$zupanija->naziv_zupanije}}</option>
#else
<option value="{{$zupanija->id}}" selected="">{{$zupanija->naziv_zupanije}}</option>
#endif
#endforeach
<option value="0" selected="">--Odaberite--</option>
idzupanije is id of the select option that needs to be selected...
javascript function "popuniGradove" is for creating select options for another select.
What I want to know is how to visual update selected option, so when window loads I see created select and showing me selected option, not this one
"--Odaberite--".
EDIT
here is screenshoot of how it looks..
I have 3 selects.. first is Zupanija (eng. "province"), Grad (eng. City), Kvart (eng. quart).. when I select zupanija, select grad is filled with options -> cities that have foregin key id_zupanija in table .. samo for kvart, after city is selected, javascript creates options with proper kvarts
... After I press submit (bnt Filtriraj) I refresh the page and filter results below... but I want my selects to save their choosen options before before submiting.. they keep showing --Odaberite-- (default option, last created) afer submiting..
If I understand you right you could consider using a Package like the old laravel 4 FormBuilder.
E. g. https://github.com/kristijanhusak/laravel-form-builder
That way you can bind every form to the respective model like so:
{!! Form::model($user, array('route' => array('user.update', $user->id))) !!}
Laravel automatically checks if input is existing in cache and will attach that data to the form.
You have to add 2 selectize, in this example we have first one for states (for example) and a second one for cities (for example). when we select a state the page send an ajax request to fetch cities in this state, then we set cities list on the cities' select.
the state select :
<select id="select-cities-state" class="selectized">
<option value="1">State 1</option>
...
</select>
the cities select :
<select id="select-cities-city" class="selectized" disabled="">
<option value=""></option>
</select>
var xhr;
var select_state, $select_state;
var select_city, $select_city;
$select_state = $('#select-cities-state').selectize({
onChange: function(value) {
if (!value.length) return;
select_city.disable();
select_city.clearOptions();
select_city.load(function(callback) {
xhr && xhr.abort();
xhr = $.ajax({
url: 'https://jsonp.afeld.me/?url=http://api.sba.gov/geodata/primary_city_links_for_state_of/' + value + '.json',
success: function(results) {
select_city.enable();
callback(results);
},
error: function() {
callback();
}
})
});
}
});
$select_city = $('#select-cities-city').selectize({
valueField: 'name',
labelField: 'name',
searchField: ['name']
});
select_city = $select_city[0].selectize;
select_state = $select_state[0].selectize;
select_city.disable();
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}}
I have set up a collection as the source for my data in a Select2 multiple select as so:
<template name="mySubjectsSelector">
<div>
<select id="mySubjects" data-placeholder="Choose your subjects" multiple>
{{#each subjects}}
<option>{{this.name}}</option>
{{/each}}
</select>
</div>
</template>
And the .js:
Template.mySubjectsSelector.subjects = function () {
console.log("Fetching subjects...");
return Subjects.find({}).fetch();
};
Template.mySubjectsSelector.rendered = function () {
console.log("mySubjectsSelector is rendered!");
$('#mySubjects')
.select2({
width: "300px"
});
};
Whenever the Subjects collection is updated, it reactively re-renders the template, and that is fine, that's how I want it to behave. The unwanted behaviour, is that it will select the first option in the list when it is re-rendered, on ALL clients!
How can I avoid the selecting of the first item when it reloads/rerenders?
What I did is create a blank first option.
<template name="mySubjectsSelector">
<div>
<select id="mySubjects" data-placeholder="Choose your subjects" multiple>
<option></option>
{{#each subjects}}
<option>{{this.name}}</option>
{{/each}}
</select>
</div>
</template>
There's probably a smarter way of doing this, but it worked for me.
EDIT:
The more involved, Meteor-specific technique I have used to preserve values of the Select2 controls, by storing the values in a Session variable. Something like this:
Template.template.rendered = function () {
// assumes 1) all Select2 controls are originally <select> tags
// and 2) all Select tags have ids assigned
$('select').each(function (i) {
if (Session.get('preserve-' + this.id)) {
$(this).val(Session.get('preserve-' + this.id));
}
});
$('.select2').select2({ /* select2 code here */ })
.on('change', function (e) {
if (e.val !== "") {
Session.set("preserve-" + e.target.id, e.val")
}
});
};
However: I may have not understood the question exactly. If you are only asking how using Select2 to allow unselected answers, try a placeholder and allowclear. From the docs:
$("#e2").select2({
placeholder: "Select a State",
allowClear: true
});
Have you tried specifying a rule to preserve the <select> and <option> elements?
Template.mySubjectsSelector.preserve({
'select[id]': function (node) { return node.id; },
'option': function (node) { return node.id; }
});
Also see the documentation.
Another problem could be that the <option> elements don't have ids. Also from the documentation:
By default, new Meteor apps automatically include the preserve-inputs
package. This preserves all elements of type input, textarea, button,
select, and option that have unique id attributes or that have name
attributes that are unique within an enclosing element with an id
attribute. To turn off this default behavior, simply remove the
preserve-inputs package.