I've a collection "Country" which displays a list of countries and their info. A book option leads a user to the "Activity" form which has dropdown fields like To,From. How do I pass the "Country" ID so that the form fields in "Activity" belong to the "Country" whose Book button the user has clicked. I think I should use a reactive var to store the country id and then perform operations to change the form fields accordingly. I'm fairly new to this and a heads up to the approach would be deeply appreciated.
The submit code for activity collection is :
Template.activitySubmit.onRendered(function () {
if (Session.get("submit-bypass") === true) {
Session.set("submit-bypass", false);
window.history.back();
}
$("#activity-goal").material_select();
});
Template.activitySubmit.events({
"submit form": function (e) {
e.preventDefault();
var title = $(e.target).find("#activity-title").val()
if (title.length === 0) {
throwError("You must have a title.");
$("activity-title").focus();
return;
}
var activty = {
title: title,
goal: parseInt($(e.target).find("#activity-goal").val())
};
Meteor.call("activityInsert", activty, function (error, result) {
if (error) {
throwError(error.reason);
return;
}
Session.set("submit-bypass", true);
Router.go("activityPage", { _id: result._id });
});
}
});
This is how you should use reactive var package
Add the package to your project, in terminal meteor add reactive-var
Open your JS file for the template, like activitySubmit.js
Declare reactive var like so
Template.activitySubmit.onRendered(function () {
this.selectedCountry = new ReactiveVar(null);
});
Then update the reactive var as needed and use it
`
Template.activitySubmit.events({
'change #country': function(e){
var country = $(e.target).val()
var instance = Template.instance();
instance.selectedCountry.set(country);
},
'submit form': function (e) {
....
var instance = Template.instance();
var country = instance.selectedCountry.get(country);
....
}
});`
If you'd like to pass the data around across mulitple files (globally), you can simply use Session. Session.set('myId', id) and Session.get('myId')
Related
,I've got a form that is automatically populated with data from Memberstack using attributes to dynamically update input values with what is stored in the member database. The user can then edit those values and submit the form to update their member data.
There's a Bio field and a Locations field, each with a Quill rich text editor. On submit, the rich text is converted to HTML and stored in Memberstack that way. If we try to pre-populate the Quills with data from Memberstack, they break and won't allow the user to edit the data. So, to display the user's current Bio and Locations, we call that data onto the page and display it as rich text, with an empty Quill editor below it for the user to be able to type in new Bio or Locations data.
However, if the Quill is empty on submit, it will replace the stored field value with "<p><br></p>".
Since there are two data fields–and two Quills–but we can only have a single function trigger on submit, we're trying to use an if, else if, else if, else statement. However, it doesn't seem to be working as intended.
We currently have a hidden text block with an id of #bio_hidden that calls in the Bio stored in Memberstack, and the same for locations with #locations_hidden - to be used as a reference
Then there's two Quills for Bio and Locations
Finally there's the actual fields that are used to update the data in the database (just called bio and locations)
The logic we're going for is:
if quillBio and quillLocations are empty:
bio = bioHidden, locations = locationsHidden
else if just quillBio is empty:
bio = bioHidden, locations = quillLocations
else if just quillLocations is empty:
bio = quillBio, locations = locationsHidden
else
bio = quillBio, locations = quillLocations
However, whether the Quills are empty or have been edited, the data that's getting passed through the form and updating the database is always just what is in the hidden fields.
Here's the script:
<script>
var quillBio = new Quill('#editor_bio', {
modules: {
toolbar: [
['bold', 'italic'],
['link'],
[{ list: 'ordered' }, { list: 'bullet' }]
]
},
placeholder: 'Type here',
theme: 'snow'
});
var quillLocations = new Quill('#editor_locations', {
modules: {
toolbar: [
['bold', 'italic'],
['link'],
[{ list: 'ordered' }, { list: 'bullet' }]
]
},
placeholder: 'Type here',
theme: 'snow'
});
var bioHidden = document.getElementById('bio_hidden');
var locationsHidden = document.getElementById('locations_hidden');
var bio = document.querySelector('textarea[name=bio]');
var locations = document.querySelector('textarea[name=locations]');
var form = document.querySelector('form[name=medical-update-form]');
form.onsubmit = function() {
// Populate hidden form on submit
if((quillBio.root.innerHTML == "<p><br></p>" || "")&&(quillLocations.root.innerHTML == "<p><br></p>" || "")) {
bio.value = bioHidden.root.innerHTML;
locations.value = locationsHidden.root.innerHTML;
}else if(quillBio.root.innerHTML == "<p><br></p>" || ""){
bio.value = bioHidden.root.innerHTML;
locations.value = quillLocations.root.innerHTML;
}
else if(quillLocations.root.HTML == "<p><br></p>" || ""){
bio.value = quillBio.root.innerHTML;
locations.value = locationsHidden.root.innerHTML;
}else{
bio.value = quillBio.root.innerHTML;
locations.value = quillLocations.root.innerHTML;
}
console.log("Submitted", $(form).serialize(), $(form).serializeArray());
// No back end to actually submit to!
return false;
};
</script>
I have a project foreign key in by Phase model. I'm having hard time Create a dependent drop-down list inside my Django admin page.
I want to when user select a project from (project drop-down) phase of that project show in second dop-down
What would be the best way to achieve this?
It would be great if the dropdowns filter items based on the value of its parent.
class Project(models.Model):
name = models.CharFieldmax_length = 100, unique= True)
short_name = models.CharField(max_length= 4, unique= True)
slug = models.SlugField(max_length= 100, allow_unicode=True, null=True, editable= False)
location = models.OneToOneField(Location, on_delete = models.SET_NULL, null= True, blank= False, verbose_name= 'موقعیت')
start_date = models.DateField(default= timezone.now, null= True, blank= True)
end_date = models.DateField(default= timezone.now, null= True, blank= True)
duration = models.IntegerField(default= 0, editable= False)
class Phase(models.Model):
title = models.CharField(max_length= 20)
class ProjectPhase(models.Model):
project = models.ForeignKey(Project, on_delete= models.CASCADE, related_name= 'phase')
phase = models.ForeignKey(Phase, on_delete=models.CASCADE, related_name= 'project')
start_date = models.DateField(default= timezone.now)
end_date = models.DateField(default= timezone.now)
duration = models.IntegerField(default= 0, editable= True)
1. import a js media file in ModelAdmin for Generaldata:
class YourModelAdmin(admin.ModelAdmin):
form = YourModelForm
#list_display = ['your fields',]
class Media:
js = ("yourapp/selectajax.js",)
admin.site.register(YourModel, YourModelAdmin)
2. create a new js file which saved yourproject/yourapp/static/yourapp/ directory or another proper directory.
jQuery(function($){
$(document).ready(function(){
$("#id_project_select").change(function(){
// console.log(obj.currentTarget.value);
$.ajax({
url:"/get_phases/",
type:"POST",
data:{project: $(this).val(),},
success: function(result) {
console.log(result);
cols = document.getElementById("id_phase_select");
cols.options.length = 0;
for(var k in result){
cols.options.add(new Option(k, result[k]));
}
},
error: function(e){
console.error(JSON.stringify(e));
},
});
});
});
});
3. create a view to process ajax
#login_required
def get_phases(request):
project = request.POST.get('project')
phases = {}
try:
if project:
prophases = Project.objects.get(pk=int(project)).phase
phases = {pp.phase.title:pp.pk for pp in prophases}
except:
pass
return JsonResponse(data=phases, safe=False)
4. add 'get_phases/ to urlpatterns.
Notice that you should modify some codes as your need.
The answer by Blackdoor is a good approach and it's the one we just implemented, but it has a couple of problems:
It's only executed when you change the main select, and I wanted the dependant select to be filtered also on page load.
Does not keep que selected item in the dependant select.
In his solution, in step 2, replace his code with this one and adapt the names (I'm using service and sub_service instead of project / phase):
jQuery(function($){
$(document).ready(function(){
var clone = document.getElementById("id_sub_service").cloneNode(true);
$("#id_service").change(function(){
update_sub_services($(this).val(), clone)
});
update_sub_services($("#id_service").val(), clone)
});
function update_sub_services(service, clone) {
$.ajax({
url:"/chained_dropdowns/get_sub_services/",
type:"GET",
data:{service: service,},
success: function(result) {
var cols = document.getElementById("id_sub_service");
cols.innerHTML = clone.innerHTML
Array.from(cols.options).forEach(function(option_element) {
var existing = false;
for (var k in result) {
if (option_element.value == k) {
existing = true
}
}
if (existing == false) {
$("#id_sub_service option[value='"+option_element.value+"']").remove();
}
})
},
error: function(e){
console.error(JSON.stringify(e));
},
});
}
});
As you can see, now instead of removing all the items from the dependant select and then refilling it (which leaves you without the selected property and any other custom property), it removes the options that should not be there.
I'm not a JS developer and I don't know jQuery so my modifications are in native JS, please feel free to improve it :)
Please
I have a form that takes a parent detail and another form which is a modal form that takes a minimal data of a particular student at the point of creating a parent. I want to be able to send the two details at the same time to the controller that handles it in the backend.
This is what I have been trying :
$("#plus").click(function () {
var student = {
"firstName": $("#sfirstName").val(),
"lastName" : $("#slastName").val(),
"middleName" : $("#smiddleName").val(),
}
console.log(student)
});
This manages the modal form and this for the normal form on the page:
$("#addParent").click(function () {
var parentForm = new FormData($('#parentForm')[0]);
parentForm.append("firstName",student[sfirstName]);
parentForm.append("middlesName", student[smiddleName]);
parentForm.append("lastName", student[slastName]);
console.log(parentForm);
})
before I will now send the forms as one the back end using Ajax... But it doesn't seem to be working ... Thanks in advance
Try to fix like this:
$("#plus").click(function () {
var student = {
firstName: $("#sfirstName").val(),
lastName : $("#slastName").val(),
middleName : $("#smiddleName").val()
} // fixed <-- we create an object literal in javascript with name-value pairs wrapped in curly braces
console.log(student)
});
And then:
$("#addParent").click(function () {
var parentForm = new FormData($('#parentForm')[0]);
parentForm.append("firstName",student[firstName]); //fixed typo
parentForm.append("middlesName", student[middleName]); //fixed typo
parentForm.append("lastName", student[lastName]); //fixed typo
console.log(parentForm);
})
I want a user to be able to type 2 inputs into a form, hit submit, and have the database send back documents with field values that match the values that were typed into the form.
If I hard code values for 'name' and 'code' variables on the last line, I get the right results and everything renders fine. So I think the problem has to do with how I'm using the variables / variable scope, or something of that nature.
more detailed description below...
I am using Meteor.
I have a form with 2 input fields, for example, product and brand
I want to send a query of the following form:
PriceList.find({'name': name, 'brandCode': code});
I have a template that renders based on the results of this query. This relies on publishing the results of the query:
if (Meteor.isServer) {
Meteor.publish('byProductAndBrand', function(){
var name = product;
var code = brand;
return PriceList.find({'name': name, 'brandCode': code});
});
}
I'm trying to use Meteor.subscribe() to change dynamically based on the form inputs:
if (Meteor.isClient) {
Template.dataSelectionForm.events({
'submit form#addDataSelectionForm': function(event, template){
event.preventDefault();
product = template.find([name='product_name']).value;
brand = template.find([name='brandCode']).value;
}
});
Meteor.subscribe('byProductAndBrand');
}
Here's the relevant code (duplicates what I wrote above, but may be less annoying to read...)
PriceList = new Meteor.Collection('PriceList');
product = 'dummyProduct';
brand = 'dummyBrandCode';
if (Meteor.isClient) {
Template.dataSelectionForm.events({
'submit form#addDataSelectionForm': function(event, template){
event.preventDefault();
product = template.find([name='product_name']).value;
brand = template.find([name='brandCode']).value;
}
});
Meteor.subscribe('byProductAndBrand');
}
if (Meteor.isServer) {
Meteor.publish('PriceList', function(){
return PriceList.find();
});
Meteor.publish('byProductAndBrand', function(){
var name = product;
var code = brand;
return PriceList.find({'name': name, 'brandCode': code});
});
}
Pass params to Meteor.subscription :
if(Meteor.isServer){
Meteor.publish('byProductAndBrand', function(product, brand){
var name = product;
var code = brand;
return PriceList.find({'name': name, 'brandCode': code});
});
}
}
if (Meteor.isClient) {
Template.dataSelectionForm.events({
'submit form#addDataSelectionForm': function(event, template){
event.preventDefault();
product = template.find([name='product_name']).value;
brand = template.find([name='brandCode']).value;
var instance = Template.instance();
if(instance.byProductAndBrandHandle != null){
instance.byProductAndBrandHandle.stop();
}
instance.byProductAndBrandHandle = Meteor.subscribe('byProductAndBrand', product ,brand);
}
});
}
It seems to me that you would be better off using dependencies instead of subscriptions. This makes sense to me in this circumstance because only the one client viewing the page is looking at this particular price list, you are not publishing this price list for multiple users as far as I can tell.
For ex:
In declarations, before if(Meteor.isClient) and if(Meteor.isServer):
var byProductAndBrandDep = new Tracker.Dependency;
Inside of priceList helper:
byProductAndBrandDep.depend();
In "submit form#addDataSelectionForm".events: function(event, templates) {
byProductAndBrandDep.changed();
Then, every time the form is submitted, every helper that has the byProductAndBrandDep.depend() function inside it automatically updates.
Trying to figure out how to do this, using Sanderson begincollectionitems method, and would like to use autocomplete with a field in each row.
I think I see how to add a row with an autocomplete, just not sure the approach for existing rows rendered with guid.
Each row has an of field that the user can optionally point to a record in another table. Each autocomplete would need to work on the html element idfield_guid.
I'm imagining using jquery to enumerate the elements and add the autocomplete to each one with the target being the unique of field for that row. Another thought is a regex that maybe let you enumerate the fields and add autocomplete for each in a loop where the unique field id is handled automatically.
Does that sound reasonable or can you suggest the right way? Also is there a reasonable limit to how many autocomplete on a page? Thanks for any suggestions!
Edit, here's what I have after the help. data-jsonurl is apparently not being picked up by jquery as it is doing the html request to the url of the main page.
$(document).ready(function () {
var options = {
source: function(request, response) {
$.getJSON($(this).data("jsonurl"), request, function (return_data) {
response(return_data.itemList);
});
},
minLength: 2
};
$('.ac').autocomplete(options);
});
<%= Html.TextBoxFor(
x => x.AssetId,
new {
#class = "ac",
data_jsonurl = Url.Action("AssetSerialSearch", "WoTran", new { q = Model.AssetId })
})
%>
And the emitted html look okay to me:
<input class="ac" data-jsonurl="/WoTran/AssetSerialSearch?q=2657" id="WoTransViewModel_f32dedbb-c75d-4029-a49b-253845df8541__AssetId" name="WoTransViewModel[f32dedbb-c75d-4029-a49b-253845df8541].AssetId" type="text" value="2657" />
The controller is not a factor yet, in firebug I get a request like this:
http://localhost:58182/WoReceipt/Details/undefined?term=266&_=1312892089948
What seems to be happening is that the $(this) is not returning the html element but instead the jquery autocomplete widget object. If I drill into the properties in firebug under the 'element' I eventually do see the data-jsonurl but it is not a property of $(this). Here is console.log($this):
You could use the jQuery UI Autocomplete plugin. Simply apply some know class to all fields that require an autocomplete functionality as well as an additional HTML5 data-url attribute to indicate the foreign key:
<%= Html.TextBoxFor(
x => x.Name,
new {
#class = "ac",
data_url = Url.Action("autocomplete", new { fk = Model.FK })
})
%>
and then attach the plugin:
var options = {
source: function(request, response) {
$.getJSON($(this).data('url'), request, function(return_data) {
response(return_data.suggestions);
});
},
minLength: 2
});
$('.ac').autocomplete(options);
and finally we could have a controller action taking two arguments (term and fk) which will return a JSON array of suggestions for the given term and foreign key.
public ActionResult AutoComplete(string term, string fk)
{
// TODO: based on the search term and the foreign key generate an array of suggestions
var suggestions = new[]
{
new { label = "suggestion 1", value = "suggestion 1" },
new { label = "suggestion 2", value = "suggestion 2" },
new { label = "suggestion 3", value = "suggestion 3" },
};
return Json(suggestions, JsonRequestBehavior.AllowGet);
}
You should also attach the autocomplete plugin for newly added rows.