i'm new to symfony, and don't know much about javascript!
i created a symfony form, and added a UniqueEntity constraint on the name and firstname, so it's not possible to add a same person twice in the database.
#UniqueEntity(fields={"firstname","name"}, message="this person already exists")
it works pretty well!
but in this case, i would like symfony to show me a javascript window with a message and 2 choices. for example: "joe smiley already exists! would you like to add an homonym? yes / no
does anyone know how to do this?
Much thanks
No, this validation is strictly server-side.
You should try some JS validation libraries like: http://rickharrison.github.io/validate.js/ (just an example)
well you could try to find if is there and error message for that field, and that will depend on how are you displaying your form fields, i strongly strongly recommend you to customize your form rendering to suit your needs, here is and example of what can you do.
<div class="control-group {% if(form_errors(form.descripcion)|length) %} error {% endif %} ">
{{ form_label(form.descripcion, null, { 'label_attr': {'class': 'control-label'} }) }}
<div class="controls">
{{ form_widget(form.descripcion) }}
{{ form_errors(form.descripcion) }}
</div>
</div>
that will render this when the validation shows and error message
<div class="control-group error ">
<label class="control-label required" for="AreaComercio_descripcion">Descripcion</label>
<div class="controls">
<input type="text" id="AreaComercio_descripcion" name="AreaComercio[descripcion]" required="required" >
<span class="help-inline">This value should not be blank.</span>
</div>
</div>
so you have to ask if is there an span sibling with the class help-inline if you dont know how to custimze your form rendering take a look at this and another advice use jquery, there are lots of people using it, jquery have an strong comunity that will help you if you are in the need, that said, i will use jquery to ilustrate what you can do to solve your problem.
if($("#AreaComercio_descripcion ~ .help-inline").length) { // here using sibling selector filter to ask if there a siblig with the class help-inline
var invalid_value = $("#AreaComercio_descripcion").val(); // asking for the field value thru its id attribute
confirm(invalid_value+" already exists! would you like to add an homonym ?");
}
using javascript confirm is the easiest way to do what you want but you can use other more flexible options like jquery dialog or you could try to install twitter bootstrap in your symfony installation, well i guess thats all i hope it will be usefull to you
Related
I've been self-teaching coding for the last 3 months or so and I have a couple of issues with a page I'm trying to make. I think my problems are a bit basic so I'm a little ashamed to ask. Any guidance would be very useful. Thank you!
I have a page that accepts recipes. Each recipe has a set number of instructions or ingredients.
The form that accepts the new recipe by default shows 3 fields to add instructions and 3 fields to add ingredients.
I'd like to implement a button that allows the user to add an extra ingredient or an extra step to the instructions.
This is what the New view file looks like in the instruction segment. It's pretty much the same for ingredients give or take a few things.
<div class="mb-3">
<label class="form-label" for="instructions" id="labelInstructions">instructions</label>
<% for(let i = 0; i<3; i++){ %>
<div class="input-group" id="instructionGroup">
<div class="input-group-prepend">
<span class="input-group-text">Step <%= i+1 %> </span>
</div>
<textarea class="form-control" aria-label=<%=`Instructions-Step-${i +1}`%> name=<%=`recipe[instructions][${i}][body]` %> id="instructions"></textarea>
</div>
<div class="valid-feedback">Looks good!</div>
<% } %>
I tried adding an onclick function to a
<button onclick="addInstruction()">+</button>
I required the file on the template and the file attempted to add the appropriate amount of divs and modify the classes and innertext, etc, etc.
But I got stuck here:
function addInstruction() {
console.log('clicked')
const label = document.getElementById('labelInstructions')
const tempDiv = document.createElement('div')
label.insertAdjacentElement("afterend", tempDiv)
}
In the console it shows that it is being clicked but it doesn't add the div I created. I know the rest of the logic isn't there yet I just wanted to see if I could see the div first, but I can't see anything.
Then I started thinking it would be easier to just add one to the loop limit. But that loop is written inside an EJS tag, I was wondering if there was a way to modify that through an onclick event. Or if there's just an entirely better way of doing this that I'm missing.
I'm very new to this, any help is appreciated. Thank you!
I think you are asking how to add some sort of div inside the DOM when a user clicks a button. To do this I would just use the .appendChild() method and append the div as a child element of the form for example document.querySelector("form").appendChild(<Div Variable>)
This implementation is using Django 4.0 and Bootstrap5 with CrispyForms.
Objective: The user selecting a value in one field determines whether another field is shown or hidden. By default, the conditional field has a value of "No". The impacted field will be shown when the user changes the conditional field to the value of "Yes". Specifically, if the user selects "Yes" for the field Recurring event the field Recurrence pattern will be shown.
Please note that the implementation of Class Based Views in the template is working great. Here's a screenshot of the form (with the conditional field requirement not working):
Existing code (relevant snippets only)
Here's what I have in models.py:
YES_NO_CHOICES = [
('No', 'No'),
('Yes', 'Yes'),
]
RECURRENCE_PATTERN_CHOICES = [
('---', '---'),
('Daily', 'Daily'),
('Weekly', 'Weekly'),
('Monthly', 'Monthly'),
('Yearly', 'Yearly'),
]
class Event(models.Model):
event_name = models.CharField(
max_length=70,
help_text='''Enter a name for the event. This is a required field and is limited to 70 characters.'''
)
recurring_event = models.CharField(
max_length=5,
choices=YES_NO_CHOICES,
default='No',
help_text='''Is this a one off event or will it recur? Selecting Yes will open up additional fields.'''
)
recurrence_pattern = models.CharField(
max_length=10,
choices=RECURRENCE_PATTERN_CHOICES,
default='---',
help_text='''Select the recurrence pattern for this event.'''
)
Here is what I have in forms.py:
class EventStaffSummaryUpdateView(UpdateView):
"""Event Staff Update view - allows staff to change event details"""
model = Event
template_name = 'events/event_staff_summary_form.html'
fields = [
'event_name',
'recurring_event',
'recurrence_pattern',
]
context_object_name = 'event'
In the event_staff_summary.html template (using inheritance) I have:
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<div id="event_name">
{{ form.event_name|as_crispy_field }}
</div>
<div id="recurring_event">
{{ form.recurring_event|as_crispy_field }}
</div>
<div id="recurrence_pattern">
{{ form.recurrence_pattern|as_crispy_field }}
</div>
</fieldset>
<div class="form-group pt-4 pb-2">
{% if page_type == 'Update' %}
<button class="btn btn-BlueGray" type="submit">Update Event</button>
{% else %}
<button class="btn btn-BlueGray" type="submit">Create Event</button>
{% endif %}
</div>
</form>
</div>
In the base.html template I am using the Google JQuery link (found on my journey as a simple way of implementing JQuery):
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
As you can see with the screenshot, the form itself is displaying perfectly. So models, form and even the html is working to this point. The update class based view is working with the DB. All that remains is to show or hide Recurrence pattern based on the value in the field Recurrence event. Which brings me to...
What have I tried so far?
Of the 10+ JS snippets I've come across and tried, here is the leading candidate that seems to be closest. I really want this to work as it makes sense to me.
<script>
$("#recurring_event").change(function() {
if ($(this).val() === "Yes") {
$('#recurrence_pattern').show();
} else {
$('#recurrence_pattern').hide();
}
});
</script>
Request
Has anyone got suggestions on how I can get this working? I've got requirements for a number of conditionally displayed fields. I'd prefer to not work from checkboxes as typically this client prefers to explicitly have the user click Yes or No as this is clearer to them (they feel there is no chance of ambiguity with a closed question and a yes/no choice).
This requirement of conditional fields in forms is implemented in many instances, so I know I'm not seeking the impossible. I am hoping that there's a simple refinement (or clean up) of the javascript snippet I've posted. I also welcome other JS suggested snippets too.
Thanks in advance for your help.
ANSWER (Feb 27)
Following the issuance of a bounty #Swati came through with a solution posted in a fiddle here: https://jsfiddle.net/L8ke03hc/ As soon as they post the answer I'll award the Bounty. I'd like to thank Tony for coming really close and getting me on the right track. The final piece of the puzzle was the .trigger event to call the change function.
<script>
$(document).ready(function() {
$("#id_recurring_event").change(function() {
if ($(this).val() === "No") {
$('#div_id_recurrence_pattern').hide();
} else {
$('#div_id_recurrence_pattern').show();
}
});
$("#id_recurring_event").trigger("change")
})
</script>
Thanks to all that came through on this one. This was a profound learning experience for me. I really need to spend some time learning JS. That said, I've got the solution. May anyone trying to build conditional logic in Django/CrispyForms benefit from this. I am so grateful for the Open Source community! <3
Update library to
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Wrap function in a DOM ready event.
Update selector to a <select> (from div). Do this by inspecting DOM.
End result:
(function($){
$(document).ready(function(){
$("#id_recurring_event").change(function() {
if ($(this).val() === "Yes") {
$('#id_recurrence_pattern').show();
} else {
$('#id_recurrence_pattern').hide();
}
});
})
})(jQuery);
You can use trigger() method to achieve this . So, whenever your page gets load called this to execute the change event which is attached on select-box .
Working code :
$(document).ready(function() {
$("#id_recurring_event").change(function() {
if ($(this).val() === "No") {
$('#recurrence_pattern').hide();
} else {
$('#recurrence_pattern').show();
}
});
$("#id_recurring_event").trigger("change")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="content-section">
<form method="POST">
<fieldset class="form-group">
<div id="event_name">
ABC ..
</div>
<div id="recurring_event">
<select id="id_recurring_event">
<option value="Yes">Yes</option>
<option value="No" selected="true">No</option>
</select>
</div>
<div id="recurrence_pattern">
somethings ..................
</div>
</fieldset>
</form>
</div>
I have a list
list = [
"Nrvana",
"Red Hot Chilli Peppers",
"R.E.M",
"Reef"
]
and on the html I am rendering the contents of this list.
<div *ngFor= "let x of list" > {{x}}
</div>
<hr/>
<div>
<textarea></textarea>
</div>
I also have a textArea , where a user can write anything he/she wants. Here is the tricky part and something I am unable to figure out. If a user uses syntax <<userText>> , a validation error should pop up stating Please use text from list inside <<>>. I can do this part but I can't figure out if I need to make a regex and if yes, please help me with it. Please ask if you need any more information.
p.s this is just something I created to get an idea of my problem, the actual project is a very long one and I am using template-driven forms
Here is a https://stackblitz.com/edit/angular-t4cfqc
Depends how you want to accomplish this and what you are exactly trying to do but you could do something like this
HTML
<textarea [(ngModel)]="textAreaText" [(ngModelChange)]="checkText()"></textarea>
.TS
textAreaText: string;
// ...
checkText() {
const regex = /(?:^|\s)<<(.*?)>>(?:\s|$)/g;
// If you only want to use certain keywords you could do something like this
const regex = /(?:^|\s)<<((keyword1)|(keyword2)|(keyword3))>>(?:\s|$)/g;
if (regex.test(this.textAreaText)) {
// do something
} else {
// do something else
}
}
You can make use of pattern attribute too. Example below
<textarea pattern="/(?:^|\s)<<(.*?)>>(?:\s|$)/g" [(ngModel)]="myTextArea" #myTextAreaModel="ngModel" required></textarea>
<div *ngIf="myTextAreaModel.errors.pattern">Your error msg here</div>
I'm trying to get my head round templating engines and if there is something suitable for my requirements.
I'd like to specify HTML and provide dynamic functionality from within the HTML itself. For example, say I had a check box on a page
<label><input type="checkbox" id="cbox1" value="first_checkbox"> This is my checkbox</label>
I'd like to specify logic within HTML so that I display more content only if that checkbox has been checked, e.g.
// if #cbox1.checked == true
<h1>The check box is checked</h1>
// else
<h1>The check box is not checked</h1>
// end
Now, it is likely that liquid will be used to provide dynamic functionality based on a data store. So it'd also be nice to use the same liquid syntax to make the form dynamic (i.e. use liquid syntax in the if conditional above).
Is it possible to write a 'js engine', perhaps using jquery, that I could include in my web pages that would allow me to use liquid syntax but bind to variables in the 'js engine' as well as the data store to make my content dynamic?
Or, is there a better approach?
I would recommend using Vue.js (https://vuejs.org/).
The template engine is very easy to learn, and provides all the functionality you mention.
Here is a working example of your scenario:
https://jsbin.com/kikaxecogo/edit?html,output
But all you need to do is initialise Vue:
new Vue({
el: '#app',
data: {
showData: false
}
});
and write the template data:
<input type="checkbox" v-model="showData">
<div v-if="showData">
This is visible using v-if
</div>
<div v-else>
The check box is not checked
</div>
I've written a introduction guide to Vue.js here https://steveedson.co.uk/vuejs-intro/
You can also bind to other text inputs, data from ajax sources etc:
<input type="text" v-model="name">
<p>Hello {{ name }}</p>
And everything will update automatically.
As an alternative to Vue.js, there is also:
https://facebook.github.io/react/
https://angularjs.org/
I just started with Angular and have lots of doubts. Right now I have a form with several fields, check image:
I want to include a link under Keywords Label-input field, something like "Advanced" and if clicked then Must not include and Must include form fields fold / unfold, or appear/dissapear.
That said, I'm not sure if I have to use ng-show or ng-hide in the fields to be shown / hidden and then use ng-click on the "Advanced" link to make change their status. Something like this for instance:
<div class="cg">
<label class="cl">Keywords</label>
<div class="controls">
<input id="id_search"
ui-select2 = "{multiple: true, simple_tags: true, tags: []}"
/>
<div class="qs"
popover-placement="left"
popover-trigger="mouseenter"
popover="Type your search"></i></div>
<a ng-click="changeStatus()">Advanced</a>
</div>
</div>
<div class="cg" ng-show="form_element.status">
<label class="cl">Must not include</label>
<div class="controls">
<input id="id_must_not_include"
class="input-block-level"
ng-disabled="tagItem.perm == 'r'"
ui-select2 = "{multiple: true, simple_tags: true, tags: []}"
ng-model="not_include"/>
<div class="qs"
ng-show="is_modal"
tooltip="Must not include words."
tooltip-placement="left"><i class="icon-question-sign"></i></div>
<span class="help-block" ng-hide="is_modal"></span>
</div>
</div>
<div class="cg" ng-show="form_element.status">
<label class="cl">Must include</label>
<div class="controls">
<input id="id_must_include"
class="input-block-level"
ng-disabled="tagItem.perm == 'r'"
ui-select2 = "{multiple: true, simple_tags: true, tags: []}"
ng-model="must_include"/>
<div class="qs"
ng-show="is_modal"
tooltip="Must include words."
tooltip-placement="left"><i class="icon-question-sign"></i></div>
<span class="help-block" ng-hide="is_modal"></span>
</div>
</div>
Is this the correct way to do this? Should I use a different approach? Some help would be great!
Thanks!
Alejandro
NOTE: For other people in similar situation, check this jsbin to see how to do this
Ng-show and ng-hide are used for manipulating the view as you would like. The error most people do when starting angular is that they directly try to target content to show/hide instead of creating states of the form. That state of the form is what will dictate the view of your form. All of this can happen in your controller to keep it nice and readable For example:
App.controller('Ctrl1', function Ctrl1 ($scope, TestService) {
$scope.isAdvancedState = false;
$scope.changeStatus = function() {
$scope.isAdvancedState = true;
}
});
You are totally on the right track with this. Angular is a little strange at first but quickly becomes pretty amazing. Stick with it :)
Thanks,
Jordan
What you have there seems like it would work alright assuming the changeStatus() call would do something like: is_modal = !is_modal; You could definitely define your template a little more simply. For example, wrap both of the advanced fields in a single div with a single ng-show="is_modal" then you wouldn't have to deal with the extra span, but it just depends on what you're trying to accomplish with your markup...
But, it looks like what you have there should work just fine.