Im learning programming with Symfony2 and I have some problems with AJAX request, but I dont know which are the errors.
I try refresh 2 combobox
Combobox1 has one list of name of some courses
Combobox2 has to refresh according to ComboBox1 id selection
Javascript
function ListarProgramas(codfacu)
{
$('#SelProgramas').html('cargando...');
var datos = "IdFacultad="+codfacu;
$.post(Routing.generate('bibliotecaportada_listar_programas'),
{IdFacultad: codfacu},
function(data)
{
if(data.responseCode == 200 )
{
$('#SelProgramas').html(data.ProgramasHtml);
}
}, "json");
}
HTML
<select name="SelEspecie" id="SelEspecie" onchange="ListarProgramas(this.value)" style="width: 350px;text-align: center">
<option value="0">SELECCIONE FACULTAD</option>
{% for facultad in facultades %}
<option value="{{ facultad.Id }}">{{ facultad.facultad }}</option>
{% endfor %}
</select>
Controller
public function listar_programasAction()
{
$request = $this->get('request');
$IdFacultad = $request->request->get('IdFacultad');
if($IdFacultad)
{
$repository = $this->getDoctrine()->getRepository("bibliotecaportadaBundle:Programas");
$Programas = $repository->findBy(array('IdFacultad' => $IdFacultad));
$ProgramasHtml = "";
foreach ($Programas as $Programa)
{
$ProgramasHtml .= "<option>".$Programa->getProgProf()."</option>";
}
$return = array("responseCode"=>200, "ProgramasHtml" => $ProgramasHtml);
}
else
{
$return=array("responseCode"=>400, "info"=>"<option>SELECCIONE PROGRAMA</option>");
}
$return = json_encode($return);//jscon encode the array
return new Response($return,200,array('Content-Type'=>'application/json'));//make sure it has the correct content type
}
Related
I wrote a piece of code that works in a way where once I select a variant on the product page, only media with the same alt text as the variant name, will display while the rest of the media is hidden. My only problem is when the product page loads it displays all the media, even if I go directly to the URL with variant ID in it. So a variant has to be selected, for my page to show only matching alt-text media. I'm wondering if there is a way to either change this or make it so that on the website load the first variant gets selected.
Here is the HTML & Liquid code I'm using:
{% unless product.has_only_default_variant %}
<variant-selector data-url="{{ product.url }}" data-section="{{ section.id }}">
{% for option in product.options_with_values %}
<label for="option-{{ section.id }}-{{ forloop.index0 }}">{{ option.name }}</label>
<select name="options[{{ option.name | escape }}]" id="option-{{ section.id }}-{{ forloop.index0 }}">
{% for value in option.values %}
<option value="{{ value | escape }}" {% if option.selected_value == value %} selected="selected" {% endif %}>{{ value }}</option>
{% endfor %}
</select>
<script type="application/json">
{{ product.variants | json }}
</script>
{% endfor %}
</variant-selector>
{% endunless %}
And here is the javascript code:
class VariantSelector extends HTMLElement {
constructor() {
super();
this.addEventListener("change", this.onVariantChange);
}
onVariantChange() {
this.getSelectedOptions();
this.getSelectedVariant();
this.updateMedia(this.currentVariant);
if (this.currentVariant) {
this.updateURL();
this.updateFormID();
this.updatePrice();
this.updateMedia();
}
}
getSelectedOptions() {
this.options = Array.from(this.querySelectorAll('select'), (select) => select.value);
console.log(this.options);
}
getVariantJSON() {
this.variantData = this.variantData || JSON.parse(this.querySelector('[type="application/json"]').textContent);
return this.variantData;
}
getSelectedVariant() {
this.currentVariant = this.getVariantJSON().find(variant => {
const findings = !variant.options.map((option, index) => {
return this.options[index] === option;
}).includes(false);
if (findings) return variant;
});
console.log(this.currentVariant);
}
updateURL() {
if (!this.currentVariant) return;
window.history.replaceState({}, '', `${this.dataset.url}?variant=${this.currentVariant.id}`);
}
updateFormID() {
const form_input = document.querySelector("#product-form").querySelector('input[name="id"]');
form_input.value = this.currentVariant.id;
}
updatePrice() {
fetch(`${this.dataset.url}?variant=${this.currentVariant.id}§ion_id=${this.dataset.section}`)
.then((response) => response.text())
.then((responseText) => {
const id = `price-${this.dataset.section}`;
const html = new DOMParser().parseFromString(responseText, 'text/html');
const oldPrice = document.getElementById(id);
const newPrice = html.getElementById(id);
if (oldPrice && newPrice) oldPrice.innerHTML = newPrice.innerHTML;
});
}
updateMedia() {
if(this.currentVariant.featured_image !=null && this.currentVariant.featured_image.alt != null) {
$('[thumbnail-color]').hide();
var selected_color = this.currentVariant.featured_image.alt;
var thumbnail_selector = '[thumbnail-color="' + selected_color + '"]';
$(thumbnail_selector).show();
} else {
$('[thumbnail-color]').hide();
}
}
}
customElements.define("variant-selector", VariantSelector);
In my project I am trying to add a dependent forms solution from this answer. My template seems to accept all data correctly, but it is not displayed in the city field.
Models
class Country(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return u'%s' % (self.name)
class City(models.Model):
name = models.CharField(max_length=50)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
def __unicode__(self):
return u'%s' % (self.name)
urls
path('getdetails/', views.getdetails, name='getdetails'),
path('new-post/', views.new_post, name='new_post'),
views
from django.shortcuts import render
from django.http import JsonResponse
from django.http import HttpResponse
def new_post(request):
countries = Country.objects.all()
[...]
def getdetails(request):
#country_name = request.POST['country_name']
country_name = request.GET['cnt']
result_set = []
all_cities = []
answer = str(country_name[1:-1])
selected_country = Country.objects.get(name=answer)
print("selected country name ", selected_country)
all_cities = selected_country.city_set.all()
print(all_cities)
for city in all_cities:
print("city name", city.name)
result_set.append({'name': city.name})
return HttpResponse(JsonResponse({'result_set': result_set}))
templates
<select name="selectcountries" id="selectcountries">
{% for item in countries %}
<option val="{{ item.name }}"> {{ item.name }} </option>
{% endfor %}
</select>
<select name="selectcities" id="selectcities">
</select>
<!-- and jquery -->
<script type="text/javascript" src="http://yourjavascript.com/7174319415/script.js"></script>
<script>
$(document).ready(function() {
$('select#selectcountries').change(function() {
var optionSelected = $(this).find("option:selected");
var valueSelected = optionSelected.val();
var country_name = optionSelected.text();
data = {
'cnt': country_name
};
ajax('/getdetails', data, function(result) {
console.log(result);
$("#selectcities option").remove();
for (var i = result.length - 1; i >= 0; i--) {
$("#selectcities").append('<option>' + result[i].name + '</option>');
};
});
});
});
</script>
As you can see, my template receives AJAX responses, but doesn't match the form, and all cities are always undefinied. How do I fix my error to show the correct cities?
https://www.awesomescreenshot.com/video/2878370?key=0b43f35b4587436854d2fbe2ae317b6f (video)
The call back to ajax returns the response. You need to access the result_set yet.
ajax('/getdetails', data, function(response) {
console.log(response);
$("#selectcities option").remove();
for (var i = response.result_set.length - 1; i >= 0; i--) {
$("#selectcities").append('<option>' + response.result_set[i].name + '</option>');
};
});
I've created an application to filter data. Inside of index, I made a filter to filter products by description, model, status, stock and category.
My category is organized through the erp_categoy table and the relationship with the product is made through erp_product_category (Receiving Product ID + Category ID).
I created a BelongsToMany relationship in the Model: Product, Category and ProductCategory.
Product Model
public function category()
{
return $this->belongsToMany('App\Category', 'erp_product_category', 'erp_productid', 'erp_categoryid');
}
Category Model
public function product()
{
return $this->belongsToMany('App\Product','erp_product_category', 'erp_categoryid', 'erp_productid');
}
Product_category Model
public function product()
{
return $this->belongsTo('App\Models\Product', 'erp_categoryid', 'erp_categoryid');
}
In my index I created a select one that lists all categories of the 'erp_category' table.
<select id="categoria" name="categoria" class="form-control" style="width: 150px;">
#foreach($cat as $categoria)
<option value="{{$categoria->erp_categoryid}}" #if($categoria->erp_categoryid === session('categoria')) selected #endif >{{$categoria->erp_name}}</option>
#endforeach
</select>
I've extended my JavaScript and stored the values in a session 'category'.
<script src="{{ asset('assets/js/ProductSearch.js') }}"></script>
<script>
var postSearch = '{{ route('product::searchPost') }}';
var searchRequest = {
'categoria' :'{{session('categoria')}}',
};
</script>
And then I did the research through JS.
$(document).on('blur', '#categoria', function(){
var categoria = $('#categoria').val();
searchRequest['categoria'] = categoria;
doSearch();
});
function doSearch() {
$.post(postSearch, {
'search_data': JSON.stringify(searchRequest),
'_token': $('meta[name=csrf-token]').attr('content'),
}
, function(data) {
$('#product-table').html(data);
});
}
I was expecting the product-table (table I created to return the values). I list my products through the category entered by select, but it returns the initial list of the index.
Product-table
<td>
#foreach($prod->category as $categoria)
{{$categoria->erp_name}}
#endforeach
</td>
Controller
public function search(Request $request)
{
$product = Product::query();
$categoria = Category::query();
if ($request->isMethod('post'))
{
$data = json_decode($request->search_data);
$categoria;
$categoria = $data->categoria;
session(['categoria' => $categoria]);
if(strlen(session('categoria')) > 0)
{
$product_ids = Product::whereHas('category', function ($query){
$query->where('erp_category.erp_categoryid', '=', session('categoria'));
})->get();
$ids = [];
foreach($product_ids as $product_data)
{
$ids[] = $product_data->erp_productid;
}
$product = $product->whereIn('erp_category.erp_categoryid', $ids);
}
$content = $product->paginate(10);
$cat = Category::all();
if ($request->isMethod('post'))
{
return view('admin.product-table')->with('product', $content)->with('cat',$cat);
} else
{
return view('admin/product')->with('product', $content)->with('cat',$cat);
}
Any suggestion?
Try to change your code to something like this:
$content = null;
if(strlen(session('categoria')) > 0) {
$product_ids = Product::whereHas('category', function ($query){
$query->where('erp_category.erp_categoryid', '=', session('categoria'));
});
$content = $product_ids->paginate(10);
$cat = Category::all();
}
if ($request->isMethod('post')) {
return view('admin.product-table')->with('product', $content)->with('cat',$cat);
} else {
return view('admin/product')->with('product', $content)->with('cat',$cat);
}
And then the view:
#if ($product !== null)
#foreach($product as $p)
<td>
#foreach($p->category as $categoria)
{{$categoria->erp_name}}
#endforeach
</td>
#endforeach
#endif
The problem in the controller must be happening when you call whereIn or something like this. Probably you don't need to query Produto again.
The second thing is that you are not using the results in the view. You are calling the relationship function.
Try this and check if it helps...
I'm creating a catalogue page. On this page I want to allow user to filter the products.
So I created a sidebar with checkboxes and input texts.
I would like that every time the user changes the filter parameters, the catalogue is updated.
this is my code:
html for sidebar (filter):
<h3>Filtri:</h3>
<b>Marca:</b><br>
{% for marca in marche %}
<input type="checkbox" title="{{ marca.nome }}" value="{{ marca.nome }}" name="marca" class="marca" onclick="filtra()"> {{ marca.nome }} <br>
{% empty %}
<p>Nessuna Marca è ancora stata inserita.</p>
{% endfor %}
<br>
<b>Portata:</b> <br>
Maggiore di
<input type="text" title="portata" name="portata" id="portata" class="textbox-filtro" maxlength="4" onblur="filtra()"> kg
<br><br>
<b>Sollevamento:</b> <br>
Maggiore di
<input type="text" title="sollevamento" id="sollevamento" class="textbox-filtro" maxlength="4" onblur="filtra()"> mt
<br><br>
<b>Trazione:</b><br>
{% for tra in trazione %}
<input type="checkbox" title="{{ tra.trazione }}" value="{{ tra.trazione }}" id="{{ tra.trazione }}" class="trazione" onclick="filtra()"> {{ tra.trazione }} <br>
{% empty %}
<p>Nessuna Trazione è ancora stata inserita</p>
{% endfor %}
<br>
<b>Idroguida:</b><br>
{% for idro in idroguida %}
<input type="checkbox" title="{{ idro.idroguida }}" value="{{ idro.idroguida }}" id="{{ idro.idroguida }}" class="idroguida" onclick="filtra()"> {{ idro.idroguida }} <br>
{% empty %}
<p>Nessuna Idroguida è ancora stata inderita</p>
{% endfor %}
As you can see, I've 5 filter groups: Marca (brand), Portata (carrying capacity), Sollevamento (lift), Trazione (traction) and Idroguida (power steering).
Every time you edit these values, the javascript function filtra() is called... so onblur for text input and onclick for checkboxes.
Here the javascript code:
<script>
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function filtra() {
var marche_selezionate = [];
var marca_check = document.getElementsByClassName('marca');
for(var i = 0; i < marca_check.length; i++){
if(marca_check[i].checked){
marche_selezionate.push(marca_check[i].value);
}
}
marche_selezionate = marche_selezionate.join(',');
var portata_selezionata = document.getElementById('portata').value;
var sollevamento_selezionata = document.getElementById('sollevamento').value;
var trazioni_selezionate = [];
var trazione_check = document.getElementsByClassName('trazione');
for(i = 0; i < trazione_check.length; i++){
if(trazione_check[i].checked){
trazioni_selezionate.push(trazione_check[i].value);
}
}
var idroguida_selezionate = [];
var idroguida_check = document.getElementsByClassName('idroguida');
for(i = 0; i < idroguida_check.length; i++){
if(idroguida_check[i].checked){
idroguida_selezionate.push(idroguida_check[i].value);
}
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
var postUrl = "{% url 'carrellielevatori:carrellielevatori' %}";
$.ajax({
url: postUrl,
type: 'POST',
data: {'marche_selezionate': marche_selezionate},
success: function(result){
alert('success');
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
</script>
so, after setting up csrf token, in way to avoid the error "403 forbidden", I start looking and all the parameters and set up the 5 variables that I would like to pass at the view in way to filter up the catalogue.
I've also added some alert in the ajax call in way to know if it's successful or not. It is. The alert with "success" appear.
The problem is that everything stops here.
In fact, it seems nothing happens in the view.
here the code of the view:
def carrellielevatori(request):
lista_carrelli = Carrelli.objects.all()
lista_marche = Marche.objects.all()
lista_trazione = Trazione.objects.all()
lista_idroguida = Idroguida.objects.all()
footerForm = MailForm()
method = 'get'
if request.is_ajax():
method = 'ajax'
return render(request,
'carrellielevatori/carrellielevatori.html',
{
'title': 'Carrelli Elevatori - Giemme Lift s.r.l.',
'footerForm': footerForm,
'year': datetime.now().year,
'carrelli': lista_carrelli,
'marche': lista_marche,
'trazione': lista_trazione,
'idroguida': lista_idroguida,
'method':method,
})
to understand if it works, I've set up the variable method to "get" and displayed it on the page. Then in the ajax "if", I change the value to "ajax".
So it should change, right? the text remains "get" and never changes to "ajax".
This is a first try to see if it works. Once I know this work I'll proceed to filter the query that with the products. But if this does not work it's useless.
PS. Yes in the ajax call I pass just one parameters. This is to know if it works. Later I will proceed adding the other parameters in the data field.
To conclude, can you please tell me why does not enter in the in if request.is_ajax()':
Is this in not the right way, how can I filter the oringal query?
I've also tried with if request.method == 'POST', but i get the same result.
Here’s how I would do it:
#csrf_exempt
def carrellielevatori(request):
lista_carrelli = Carrelli.objects.all()
lista_marche = Marche.objects.all()
lista_trazione = Trazione.objects.all()
lista_idroguida = Idroguida.objects.all()
footerForm = MailForm()
method = 'get'
if request.is_ajax():
method = 'ajax'
return JsonResponse({
'title': 'Carrelli Elevatori - Giemme Lift s.r.l.',
'footerForm': footerForm,
'year': datetime.now().year,
'carrelli': lista_carrelli,
'marche': lista_marche,
'trazione': lista_trazione,
'idroguida': lista_idroguida,
'method':method,
})
In the JS:
function filtra() {
var marche_selezionate = [];
var marca_check = document.getElementsByClassName('marca');
for(var i = 0; i < marca_check.length; i++){
if(marca_check[i].checked){
marche_selezionate.push(marca_check[i].value);
}
}
marche_selezionate = marche_selezionate.join(',');
var portata_selezionata = document.getElementById('portata').value;
var sollevamento_selezionata = document.getElementById('sollevamento').value;
var trazioni_selezionate = [];
var trazione_check = document.getElementsByClassName('trazione');
for(i = 0; i < trazione_check.length; i++){
if(trazione_check[i].checked){
trazioni_selezionate.push(trazione_check[i].value);
}
}
var idroguida_selezionate = [];
var idroguida_check = document.getElementsByClassName('idroguida');
for(i = 0; i < idroguida_check.length; i++){
if(idroguida_check[i].checked){
idroguida_selezionate.push(idroguida_check[i].value);
}
}
var postUrl = "{% url 'carrellielevatori:carrellielevatori' %}";
$.post(postUrl, {'marche_selezionate': marche_selezionate},
function(result){
alert('success');
}).fail(function (data, status, xhr) {
alert(xhr.status);
alert(thrownError);
});
}
I have a function in twig which selects some values from db and displays a selectbox. I am trying to change the content of the div. The problem is that with innerHTML {{ creates a new line without quote and this is shown like error. It doesnt get the select box because it doesn't have quotes.
$(document).ready(function() {
$type = $("select[name='dtl[USER_TYPE]']");
$type.change(function() {
if ($(this).val() == "AUTOR") {
var content = '{{ mm.select(holdersdata, data.USER_TYPE_OBJECT_KOD, 'dtl[USER_TYPE_OBJECT_KOD]') }}';
document.getElementById("kodi").innerHTML = '"'+ content + '"';
}
});
});
macros.twig
<select data-placeholder="{{ translate('ZGJIDH_NJE') }}" name="{{ name }}" class="form-control input-sm chosen-select">
<option {% if not options.allowNull %}disabled{% endif %} selected value>{{ translate('ZGJIDH_NJE') }}</option>
{% for f in dataset %}
<option value="{{ f[kodField] }}" {% if f[kodField] | trim == selectedVal %}selected{% endif %}>
{% if f[labelField] %}
{{ f[labelField] }} {% if f[kodField] %}— ({{ f[kodField] }}){% endif %}
{% else %}
{{ f[kodField] }}
{% endif %}
</option>
{% endfor %}
</select>
EDIT
this is shown in console. {{ creates a new line without quotes:
var content = "
<select data-placeholder="Zgjidh nje..." name="dtl[USER_TYPE_OBJECT_KOD]" class="form-control input-sm chosen-select">
<option disabled selected value>Zgjidh nje...</option>
</select>
The problem is that your twig syntax is breaking the javascript syntax. See below, just change the 'to "
if ($(this).val() == "AUTOR") {
var content = '{{ mm.select(holdersdata, data.USER_TYPE_OBJECT_KOD, 'dtl[USER_TYPE_OBJECT_KOD]') }}';
document.getElementById("kodi").innerHTML = '"'+ content + '"';
}
Correct code :
if ($(this).val() == "AUTOR") {
var content = "{{ mm.select(holdersdata, data.USER_TYPE_OBJECT_KOD, 'dtl[USER_TYPE_OBJECT_KOD]') }}";
document.getElementById("kodi").innerHTML = '"'+ content + '"';
}
Due to the contents of your output JS is breaking as well. U can solve this by extending twig :
$filter = new Twig_SimpleFilter('escape_for_js', function ($string) {
$needles= array(
"\n",
"\r",
'"',
);
$replaces = array(
'',
'',
'\"',
);
return str_replace($needles, $replaces, $string);
});
Add this filter into twig :
$twig = new Twig_Environment($loader);
$twig->addFilter($filter
Using this filter :
var content = "{{ mm.select(holdersdata, data.USER_TYPE_OBJECT_KOD, 'dtl[USER_TYPE_OBJECT_KOD]') | escape_for_js }}";
More about extending twig here
No need to extend Twig yourself. Just use json_encode:
var content = {{ mm.select(holdersdata, data.USER_TYPE_OBJECT_KOD, 'dtl[USER_TYPE_OBJECT_KOD]') | json_encode }};
Notice the lack of quotes. json_encode will add them for you.