How to pass AJAX arguments to the extbase action? - ajax

Now that I managed to get values from the database, I want to specify more what I want to be passed.
From a select box that reacts to the event function below, I want to read out a value (uid of a record) and pass it to my ajaxAction:
var uid;
$('#mySelectBox').change(function() {
arguments = $(this).attr('value');
var uri = '<f:uri.action arguments="{uid: '+uid+'}" action="ajax" controller="Mycontroller1" pageType="89657201" />';
jQuery.getJSON(uri, function(result) {
// do something
});
});
I tried it with arguments, no idea if that is the right way. Additionally, as Marcus Biesioroff suggested, I should save my JS into a separate file, but then I would have to write the uri on my own instead of the Fluid way, right?
My ajaxAction looks like this:
public function ajaxAction($uid) {
$dataFromRepo = $this->myRepository->findByUid($uid);
$resultArray = array(
"field1" => $dataFromRepo->getField1(),
"field2" => $dataFromRepo->getField2(),
"field3" => $dataFromRepo->getField3(),
"field4" => $dataFromRepo->getField4(),
);
return json_encode($resultArray);
}
I'm sure that the uid is not passed correctly, everything else works.

There are some mistakes:
You can't break vievhelper's syntax with JS even if it's placed in view, you need to pass full path of the action from <f:uri.action />
you cannot place this JS in view, because it contains curly brackets there's other description of the issue
you need to call ajax function from external file and pass to it action's link and uid separately, and then add the
in the view:
<script type="text/javascript">
var actionsPathFromViewHelperSetInTheView
= '<f:uri.action action="ajax" controller="Mycontroller1" pageType="89657201" />';
</script>
<script type="text/javascript" src="path/to/ext/Public/yourExternal.js"></script>
<!-- of course this field may/should be created with Fluid's viewhelper -->
<select id="mySelectBox" onchange="performAjaxCall(this)">
<option value="1">Item 1</option>
<option value="2">Item 2</option>
<option value="3">Item 3</option>
</select>
in the yourExternal.js (of course you need to change tx_yourextkey_yourplugin prefix to your own)
function performAjaxCall(selectFieldObj) {
$.ajax({
url: actionsPathFromViewHelperSetInTheView,
data:{
"tx_yourextkey_yourplugin[uid]":selectFieldObj.value
},
success:function (data) {
// do something with your json
alert('Load was performed.');
}
});
}
in your controller:
public function ajaxAction() {
// try to always validate the incoming arguments
if (!$this->request->hasArgument('uid') || intval($this->request->getArgument('uid')) == 0) {
header('HTTP/1.1 400 Bad Request');
return json_encode(array('error'=> 'Bad request'));
}
$uid = intval($this->request->getArgument('uid'));
$dataFromRepo = $this->myRepository->findByUid($uid);
if ($dataFromRepo == null) {
header('HTTP/1.1 404 Not found');
return json_encode(
array('error'=> 'Not found or you have no access or something else... happens...')
);
}
$resultArray = array(
"field1" => $dataFromRepo->getField1(),
// etc...
);
return json_encode($resultArray);
}

Related

vue-18n - how to force reload in computed function when changing language

I am using vue-i18n but I also have some content which is stored in database. I would like my text to be updated when the user changes the language.
I am using laravel and vuejs2.
Thanks in advance, I am not super familiar with vuejs yet. I hope it's clear enough.
in ContenuComponent.vue
<template>
<div>
{{$i18n.locale}} <== this changes well
<div v-html="textcontent"></div>
<div v-html="textcontent($i18n.locale)"></div> <== this won't work, I am wondering how to put params here (more like a general quetsion)
</div>
</template>
<script>
export default {
name:'contenu',
props: {
content: {
type: String,
default: '<div></div>'
}
},
computed: {
textcontent: function () {
console.log(navigator.language); <== this gives me the language as well, so i could use it if I can make it reload
var parsed = JSON.parse(this.content);
parsed.forEach(element => {
if(navigator.language == element['lang']){
return element['text'];
}
});
}
}
}
</script>
in ContentController
public function getcontent(){
$content = DB::connection('mysql')->select( DB::connection('mysql')->raw("
SELECT text, lang from content
"));
return view('myvue', ['content' => json_encode($content)]);
}
in content.blade.php
<div id="app">
<contenu content="{{ $content }}"></contenu>
</div>
You SHOULD NOT pass parameters to computed props! They are not methods and you should create method instead:
methods: {
textcontent () {
var parsed = JSON.parse(this.content)
parsed.forEach(element => {
if (navigator.language == element['lang']){
return element['text']
}
})
}
}
Also you should consider ES6 syntax:
methods: {
textcontent () {
var parsed = JSON.parse(this.content)
const content = parsed.find(element => navigator.language == element['lang'])
return content['text']
}
}
Much cleaner!
Please make sure to read about computed props and how they are different than methods or watchers: docs

How to pass values from form to datatables

I am playing with laravel and datatables.
Here is the table with filtering option in the form I want to understand.
Basically configured routes and controllers as in the example but cannot dynamically get values from a drop down list below via ajax.
<select class="form-control" id="asortment" name="asortment">
<option value="68">A</option>
<option value="5">B</option>
...
Javascript responsible for ajax communication:
<script type="text/javascript" charset="utf8" src="//cdn.datatables.net/1.10.16/js/jquery.dataTables.js"></script>
<script>
$(document).ready( function () {
$('#datatable').DataTable({
"processing": true,
"serverSide": true,
"ajax": {
url: "{{ route('api.products.index') }}",
data: function (d) {
d.product = $('input[name=product]').val();
d.fromDate = $('input[name=fromDate]').val();
d.toDate = $('input[name=toDate]').val();
d.asortment = $('input[name=asortment]').val();
},
},
"columns": [
{ "data": "Name", },
{ "data": "Type" },
{ "data": "Asortment" },
{ "data": "Margin" }
]
});
});
$('#search-form').on('submit', function(e) {
oTable.draw();
e.preventDefault();
});
</script>
My API controller looks like this:
class APIController extends Controller
{
public function getProducts(Request $request)
{
$product = $request->input('product');
$fromDate = $request->input('fromDate');
$toDate = $request->input('toDate');
$asortment = $request->input('asortment');
$query = DB::select('exec test.dbo.Products #startDate = ?, #endDate = ?, #asortment = ?, #produkt = ?', [$fromDate, $toDate, $asortment, $product]);
return datatables($query)->make(true);
}
}
Problem: Ajax takes 3 values (product, fromDate, toDate) but doesn't accept asortment, which is in select form.
I need a little help on why...:)
Instead of Using $('input[name=asortment]').val(); change it to $("#asortment").val(); (Pure jQuery way!).
$('input[name=YOUT_NAME]').val(); doesn't work with Radio Button/Select/Checbox.
val() allows you to pass an array of element values. This is useful
when working on a jQuery object containing elements like , , and s inside of a
. In this case, the inputs and the options having a value that
matches one of the elements of the array will be checked or selected
while those having a value that doesn't match one of the elements of
the array will be unchecked or unselected, depending on the type. In
the case of s that are part of a radio group and
s, any previously selected element will be deselected.
Setting values using this method (or using the native value property)
does not cause the dispatch of the change event. For this reason, the
relevant event handlers will not be executed. If you want to execute
them, you should call .trigger( "change" ) after setting the value.
This is mentioned in jQuery's documentation.

Ajax call not returning a response, just reloads page

I have a Symfony 3 CRM and I use ajax calls to action the removal of items throughout the system. It uses a single call and then uses a switch statement to determine what it is the user is attempting to delete and handles it accordingly.
However, for some strange reason one particular type of item doesn't seem to work, it just reloads the page.
Here is the trigger button (I am implementing bootstrap confirmation):
<a href="" data-type="unit" id="{{ unit.id }}"
data-toggle="confirmation-singleton"
data-btn-ok-class="btn btn-xs btn-success"
data-btn-cancel-class="btn btn-xs btn-danger"
class="btn btn-xs btn-danger remove-item">
<i class="fa fa-remove no-override"> </i>
</a>
My ajax call for removal of items:
$('.remove-item').confirmation({
rootSelector: '[data-toggle=confirmation-singleton]',
container: 'body',
onConfirm: function() {
var type = $(this).attr('data-type');
var id = $(this).attr('id');
var data = type + '|' + id;
$.ajax( '/app_dev.php/ajax-call/remove-item/' + data )
.done( function(response) {
if(response != 'success') {
if(response == 'units_exist') {
alert("You cannot delete this item as there are units already linked to it.");
} else if(response == 'no_property') {
alert("Sorry! Property could not be found.");
} else if(response == 'bookings_exist') {
alert("Sorry! This unit has bookings. Please delete the bookings first.");
}
}
});
return false;
},
onCancel: function() {
return false;
}
});
And on the PHP side, for this particular example:
$data = $request->get('data');
$parts = explode("|",$data);
$type = $parts[0];
$id = $parts[1];
// using switch on $type
case 'unit':
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('AppBundle:Unit');
$booking_repo = $em->getRepository('AppBundle:Booking');
$bookings = $booking_repo->findBy(array('unitId' => $id)); // check to see if any bookings exist
if(!empty($bookings)) {
return new Response('bookings_exist');
} else {
$item = $repo->findOneBy(array('id' => $id));
if(!empty($item)) {
$em->remove($item);
$em->flush();
}
}
break;
In this example, it SHOULD return 'bookings_exist' and if I directly go to the URL in the browser, it does display this message - however, all it does it reload the page instead of throwing the alert as stipulated in the ajax call. I know this call works as it does successfully delete other items in the CRM, it just seems to be when it cannot delete it due to a condition such as this.
I may be missing something really obvious here, so any help is appreciated.
For jQuery Ajax, use success and error handlers
Other handlers in jQuery's Ajax object are unreliable at best, and vary in their behavior and support between versions and browsers.
Prevent Default is generally a good idea with ajax handled events
Should jQuery fail, and NOT return false, the element will do it's default behavior, which in your case is which reloads the page.
onConfirm: function(e) {
e.preventDefault();
var type = $(this).attr('data-type');
var id = $(this).attr('id');
var data = type + '|' + id;
$.ajax( '/app_dev.php/ajax-call/remove-item/' + data )
.success( function(response) {
if (response.errorMessage) {
alert(response.errorMessage);
}
})
.error( function(xhr, status, error) {
console.log(status + '\n' + error);
})
;
return false;
}
PHP Side, build a JSONResponse
if(!empty($bookings)) {
return new JsonResponse([
'errorMessage' => 'Sorry! Property could not be found.'
);
}
instead of just adding .done() you should also use
.fail(function( jqXHR, textStatus, errorThrown ) {});
to catch any errors.
If the bookings is not empty then the function will return the new response 'booking_exist' and stop ... it will not proceed to next statments .
So if you need to delete the item use this code instead :
if(empty($bookings)) {
return new Response('bookings_not_exist');
} else {
$item = $repo->findOneBy(array('id' => $id));
if(!empty($item)) {
$em->remove($item);
$em->flush();
}

Vue.js Component combined with Laravel Form Validation (i.e. passing an initial value for data)

After much Googling and finding the Vue.js forum down, I am ready to give up.
I'm creating a Postcode Lookup component, and everything was working well until I tried to combine it with Laravel's form validation - particularly when there's an error, and the form re-fills the old values.
Hopefully I cover everything here. I have a form input partial that I use which generates every form input. It also uses Laravel's old(...) value if present.
The issue is because there's a default value (in this case for postcode and address) of an empty string, this overrides the value attribute of Postcode input, and the content of the Address textarea.
In made up land, the ideal would be:
data : function() {
return {
postcode : old('postcode'),
address : old('address'),
addresses : [],
hasResponse : false,
selectedAddress : ''
};
},
So that's what I'm trying to replicate.
I can probably replace validation with Ajax validation, but my form partial changes the appearance of fields with an error slightly, so this would be messy
From my understanding:
I can't set an initial data value, as this will override the input value.
I can set a prop, but this is immutable
Any help I can find suggests 'using a computed property which determines its value from the prop' but if you literally do that, it doesn't update.
Here's what I have so far:
<so-postcode-lookup initial-postcode="{{ old('postcode') }}" initial-address="{{ old('address') }}"></so-postcode-lookup>
/**
* Allow user to select an address from those found in the postcode database
*/
Vue.component('so-postcode-lookup', {
name : 'so-postcode-lookup',
template : '#so-postcode-lookup-template',
props : ['initialPostcode', 'initialAddress'],
data : function() {
return {
postcode : '',
address : '',
addresses : [],
hasResponse : false,
selectedAddress : ''
};
},
computed : {
currentAddress : function() {
if (this.address !== '') {
return this.address;
} else {
return this.initialAddress;
}
},
currentPostcode : function() {
if (this.postcode !== '') {
return this.postcode;
} else {
return this.initialPostcode;
}
},
hasAddresses : function() {
return this.addresses.length;
},
isValidPostcode : function() {
return this.postcode !== '' && this.postcode.length > 4;
},
isInvalidPostcode : function() {
return !this.isValidPostcode;
}
},
methods : {
fetchAddresses : function() {
var resource = this.$resource(lang.ajax.apiPath + '/postcode-lookup{/postcode}');
var $vm = this;
var element = event.currentTarget;
// Fetch addresses from API
resource.get({ postcode : this.postcode }).then(function(response) {
response = response.body;
if (response.status == 'success') {
// Update addresses property, allowing select to be displayed
$vm.addresses = response.data;
} else {
$vm.addresses = [];
}
this.hasResponse = true;
});
},
setAddress : function() {
this.address = this.selectedAddress;
}
}
});
<template id="so-postcode-lookup-template">
<div class="row">
#include('partials.input', [
'label' => trans('register.form.postcode'),
'sub_type' => 'postcode',
'input_id' => 'postcode',
'autocorrect' => false,
'input_attributes' => 'v-model="currentPostcode"',
'suffix_button' => true,
'suffix_button_reactive' => trans('register.form.postcode_button_reactive'),
'suffix_text' => trans('register.form.postcode_button'),
'required' => true,
'columns' => 'col-med-50',
'wrapper' => 'postcode-wrapper'
])
<div class="col-med-50 form__item" v-show="hasResponse">
<label for="address-selector" class="form__label" v-show="hasAddresses">{{ trans('forms.select_address') }}</label>
<select id="address-selector" class="form__select" v-show="hasAddresses" v-model="selectedAddress" #change="setAddress">
<template v-for="address in addresses">
<option :value="address.value">#{{ address.text }}</option>
</template>
</select>
<so-alert type="error" allow-close="false" v-show="!hasAddresses">{{ trans('forms.no_addresses') }}</so-alert>
</div>
#include('partials.input', [
'label' => trans('register.form.address'),
'input_id' => 'address',
'type' => 'textarea',
'input_attributes' => 'v-model="currentAddress"',
'required' => true
])
</div>
</template>
If I try this, and set the model of the inputs to currentPostcode and currentAddress respectively, I seem to get an infinite loop.
I think I'm overthinking this somehow.
You can't bind directly to a prop but you can set an initial value using the prop and then bind to that, which is the way to go if you need a two way binding:
Vue.component('my-input', {
props: {
'init-postcode': {
default: ""
}
},
created() {
// copy postcode to data
this.postcode = this.initPostcode;
},
data() {
return {
postcode: ""
}
},
template: '<span><input type="text" v-model="postcode"> {{ postcode }}</span>'
});
Then just do:
<div id="app">
<my-input init-postcode="{{ old('postcode') }}"></my-input>
</div>
Here's the fiddle: https://jsfiddle.net/vL5nw95x/
If you are just trying to set the initial values, but don't need a two way binding, then you can reference the prop directly - as you won't be applying any changes - using v-bind:value:
Vue.component('my-input', {
props: {
'init-postcode': {
default: ""
}
},
template: '<span><input type="text" :value="initPostcode"> {{ postcode }}</span>'
});
And the markup:
Here's the fiddle: https://jsfiddle.net/pfdgq724/
Im working in a easy way to do that using laravel 5.4 controller to send the data directly
In Laravel view:
<input class="form-control" id="ciudad" name="ciudad" type="text" v-model="documento.ciudad" value="{{ old('ciudad', isset($documento->ciudad) ? $documento->ciudad : null) }}" >
in vue.js 2.0
data: {
documento: {
ciudad: $('#ciudad').val(),
},
},
In Laravel Controller
$documento = ReduJornada::where("id_documento",$id)->first();
return view('documentos.redujornada')->with(compact('documento'));

Bootstrap Typeahead with AJAX source (not working)

I'm trying to implement a search bar dropdown using bootstrap v3.0.0 with typeahead.js.
My search bar will take a student's firstname and lastname. I'm using a MYSQL database which consists of a table called practice with afirstname, alastname, aid as columns. The search bar should not only contain the firstname and lastname in the dropdown, but also the id associated with it in a second row. I've read all the examples on the typeahead.js page and I'm unable to do it with ajax call.
Below is the code of my index.php
JS
<script type="text/javascript">
$(document).ready(function() {
$('.cr.typeahead').typeahead({
source: header: '<h3>Select</h3>',
name: 'accounts',
source: function (query, process) {
return $.getJSON(
'localhost/resultly/source.php',
{ query: query },
function (data) {
return process(data);
});
});
});
</script>
HTML:
<body>
<div class="container">
<br/><br/>
<input type="text" name="query" class="form-control cr typeahead" id="firstname" />
<br/><br/>
</div>
</body>
Code for source.php : This should return the firstname and lastname from my database in the form of a json string or object?
<?php
$query = $_POST['query'];
try {
$conn = new PDO('mysql:host=localhost;dbname=practice','root','');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
$stmt->execute();
}
catch (PDOException $e) {
echo 'ERROR:' . $e->getMessage();
}
foreach ($stmt as $row) {
$afirstname[] = $row['afirstname'];
$alastname[] = $row['alastname'];
}
echo json_encode($afirstname);
echo json_encode($alastname);
?>
result:
http://oi41.tinypic.com/50moi1.jpg
Nothing shows up. I've tried adding a prefetch:
prefetch: {
url: 'localhost/resultly/source.php',
filter: function(data) {
r1 = [];
for (var i = 0; i < data.length; i++) {
r1.push({
value: data[i].afirstname,
tokens: [data[i].afirstname, data[i]alastname],
afirstname: data[i].afirstname,
alastname: data[i].alastname,
template: '<p>{{afirstname}} - {{alastname}}</p>',
});
}
return r1;
}
}
Please do provide a solution or an example which I could refer.
Update:
The source.php should return a list of json encoded data. I debugged by looking at the output that the source.pho created. What I did wrong was whenever I was supposed to put a url I did localhost/source.php instead of just source.php.
Solution provided by Bass Jobsen works and now I have run into another problem.
I'm using
if(isset($_POST['query']))
{ $q_uery = $_POST['query'];
$query = ucfirst(strtolower($q_uery))};
to take the user's data and use it for searching logic
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
The updated source.php is http://pastebin.com/T9Q4m10g
I get an error on this line saying Notice: Undefined variable: stmt I guess the $query is not being initialized. How do I get this to work. Thanks.
Update 3
I used prefetch: instead of 'remote:' that did all the matching.
Your return is not correct:
echo json_encode($afirstname);
echo json_encode($alastname);
See for example Twitter TypeAhead.js not updating input
Try echo json_encode((object)$stmt);, see: typeahead.js search from beginng
Update
I tried echo json_encode((object)$stmt);still doesn't work.
Do you use any kind of debugging? What does? source.php return? Try to follow the steps from
typeahead.js search from beginng without the filter.
html:
<div class="demo">
<input class="typeahead" value="" type="text" spellcheck="off" autocomplete="off" placeholder="countries">
</div>
javascript:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10
});
php (source.php):
<?php
$people = array();
$people[] = array("lastname"=>"Inaw",
"firstname"=>"Dsajhjkdsa");
$people[] = array("lastname"=>"Dsahjk",
"firstname"=>"YYYsgbm");
$people[] = array("lastname"=>"Dasjhdsjka",
"firstname"=>"JHJKGJ");
$datums = array();
foreach($people as $human)
{
$datums[]=(object)array('value'=>$human['firstname'],'tokens'=>array($human['firstname'],$human['lastname']));
}
echo json_encode((object)$datums);
This should work
update2
Thanks, it worked. How do I display 2 or more 'value'?
add some values to your datums in source.php:
foreach($people as $human)
{
$datums[]=(object)array
(
'value'=>$human['firstname'],
'tokens'=>array($human['firstname'],$human['lastname']),
'firstname'=>$human['firstname'],
'lastname'=>$human['lastname']
);
}
firstname and lastname now are field you csn use in your templates
Add a template and template engine to your javascript declaration:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10,
template: [
'<p>{{firstname}} - {{lastname}}</p>'
].join(''),
engine: Hogan
});
The above make use of https://github.com/twitter/hogan.js. You will have to include the template engine by javascript, for example:
<script src="http://twitter.github.io/typeahead.js/js/hogan-2.0.0.js"></script>
It is working for me. please follow below step.
Please add below Js and give proper reference.
bootstrap3-typeahead
--- Ajax Call ----
$("#cityId").keyup(function () {
var al = $(this).val();
$('#cityId').typeahead({
source: function (valuequery, process) {
var states = [];
return $.ajax({
url: http://localhost:4000/GetcityList,
type: 'POST',
data: { valueType: "", valueFilter: valuequery },
dataType: 'JSON',
success: function (result) {
var resultList = result.map(function (item) {
states.push({
"name": item.Value,
"value": item.Key
});
});
return process(states);
}
});
},
});
});
---- Cs Code ---
public JsonResult SearchKeyValuesByValue(string valueType, string valueFilter)
{
List<KeyValueType> returnValue = SearchKeyValuesByValue(valueType, valueFilter);
return Json(returnValue);
}
Auto suggest of Bootstrap typehead will get accept only "name" and "value" so create reponse accordinly

Resources