I'm having trouble implementing JQuery UI Autocomplete in CakePHP 2.0. Want to display a list of Items on a Grocery list view to allow users to select an item already in the database instead of creating a new one.
Application Jquery:
////file:app/webroot/js/application.js
$(document).ready(function(){
// Caching the Item textbox:
var item = $('#item');
// Defining a placeholder text:
item.defaultText('Search for items');
// Using jQuery UI's autocomplete widget:
item.autocomplete({
minLength: 1,
source: 'http://localhost/groceries/groclists/search'
////**part of the problem was here, needs to be full source**
});
});
// A custom jQuery method for placeholder text:
$.fn.defaultText = function(value){
var element = this.eq(0);
element.data('defaultText',value);
element.focus(function(){
if(element.val() == value){
element.val('').removeClass('defaultText');
}
}).blur(function(){
if(element.val() == '' || element.val() == value){
element.addClass('defaultText').val(value);
}
});
return element.blur();
}
Item form in View:
<div class="items form">
<?php echo $this->Form->create('Item', array('action' => 'search')); ?>
<?php echo $this->Form->input('item', array('type' => 'text', 'id' => 'item', 'label' => 'Search')); ?>
<?php echo $this->Form->end(__('Submit', true)); ?>
</div>
Items Controller Search():
public function search() {
if ($this->RequestHandler->isAjax()) {
Configure::write('debug', 0);
$this->autoRender = false;
$query = $_GET['term'];
$searchitems = $this->Item->find('all', array(
'conditions' => array('Item.name LIKE' => '%' . $query . '%')));
$i = 0;
foreach ($searchitems as $searchitem) {
$response[$i]['value'] = $searchitem['Item']['name'];
$response[$i]['label'] = $searchitem['Item']['id'];
$i++;
}
echo json_encode($response);
} else {
if (!empty($this->data)) {
$this->set('items', $this->paginate(array('Item.name LIKE' => '%' . $this->data['Item']['name'] . '%')));
}
}
}
I'm at a loss, any input welcome.
After making the above change to the Application.js I'm now getting a response into my webpage. It has the correct number of results based off of what is included in the database at the moment, however it's a null response. From Firebug the response is as follows:
[{"value":null,"label":null},{"value":null,"label":null},{"value":null,"label":null},{"value":null,"label":null}]
Here are my Response Headers:
Response Headers
Date Sun, 18 Sep 2011 14:48:37 GMT
Server Apache/2.2.11 (Win32) PHP/5.3.0
X-Powered-By PHP/5.3.0
Content-Length 113
Keep-Alive timeout=5, max=100
Connection Keep-Alive
Content-Type text/html; charset=UTF-8
Request Headers
Host localhost
User-Agent Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2
Accept application/json, text/javascript, */*; q=0.01
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip, deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection keep-alive
X-Requested-With XMLHttpRequest
Referer http://localhost/groceries/groclists/view/3
Cookie CAKEPHP=hu7ksthrlfms0lqod3rdq296f5
I'm not particularly clear about what you're asking, but here's the Javascript I've used to do this in CakePHP 1.2 and 1.3:
$.ajax({
url: '/api/v1/zip_codes/utilities/' + zip + '/' + type + '.json',
type: 'GET',
dataType: 'json',
success: function( data, status ) {
var utility_type = data.Type.name;
var $provider_name = $('#Building' + utility_type + 'ProviderName');
var $provider_id = $('#Building' + utility_type + 'ProviderId');
// Massage the Cake data into something autocomplete-friendly
var $friendly = $.map( data.Utilities, function( util ) {
return { label: util.Utility.name, value: util.Utility.id };
});
// If more than one, populate the provider autocomplete options
$provider_name.autocomplete({
source: $friendly, // use the autocomplete-friendly data
minLength: 0,
focus: function( event, ui ) {
$provider_name.val( ui.item.label );
return false;
},
select: function( event, ui ) {
$provider_name.val( ui.item.label );
$provider_id.val( ui.item.value );
return false;
}
}).data( 'autocomplete' )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( '<a>' + item.label + '</a>' )
.appendTo( ul );
};
});
This snippet retrieves the name and ID of utility companies operating in a given zip code (just to provide a little context). For more information, a question I asked about this same issue may help.
Related
Hello fellow programmers,
I've got the following problem. I do a post request with axios as shown below:
componentDidMount() {
const config = {
headers: { Authorization: `Bearer ${Auth.getToken()}` },
};
const urlCategories = "http://localhost:8090/category";
axios.get(urlCategories, config).then((res) => {
const categories = res.data;
this.setState({ categories });
console.log(this.state.categories);
});
const urlTricks = "http://localhost:8090/trick/" + Auth.parseJwt().sub;
axios.get(urlTricks, config).then((res) => {
const tricks = res.data;
this.setState({ tricks });
console.log(this.state.tricks);
});
}
This works! :D
Then I want to do the same but later, so I almost copied this BUT...
I get a 401 while I can't see any real difference between the two. I even asked my teacher and he didn't know the answer to it.
handleChecked = () => {
if (this.state.learned) {
this.setState(
{
learned: false,
},
() => {
console.log("Should be false and is: " + this.state.learned);
const config = {
headers: { Authorization: `Bearer ${Auth.getToken()}` },
};
axios
.post(
"http://localhost:8090/user/" +
Auth.parseJwt().sub +
"/" +
this.props.id +
"/" +
this.state.learned,
config
)
.then(() => {
console.log(this.props.name + " set to: " + this.state.learned);
});
}
);
} else { }
The weird thing is; it works in Postman so my conclusion is there must be something wrong with the front-end. Back-end should be okay. If you're curious: Auth.parseJwt().sub gets the username (I know it's a weird name for a username). Another weird thing is when I copy the URL in the Chrome Inspect overview and use it in Postman, it works...
Does anyone know or see what is wrong with this code?
My name is Appeltaart and if it works in postman, the back-end should be fine just as you said. You can start your application from scratch or try this :D
axios.post(`http://localhost:8090/user/${Auth.parseJwt().sub}/${this.props.id}/${this.state.learned}`, {
headers: {
Authorization: `Bearer ${Auth.getToken()}`,
"Content-Type": "application/json"
}
}).then(() => {
console.log(this.props.name + " set to: " + this.state.learned);
});
Friendly Greetings,
Your Applepie
I wanted to send a POST request to my backend with webview. How do i get but i got the above error.
From the docs:
" headers (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests."
How do i get a work-around for this ?
this is my code
const data = JSON.stringify({
type: 'car',
plate_number: 'c123'
});
return (
<WebView
source={{
uri:'https://api-stg.caspian.id/user/vehicles/add',
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: '54dc3c3c*******'
},
body: data
}}
/>
);
One way to get around this limitation is by performing this POST request in the React Native side of things, waiting for this response to arrive, and then feed the response HTML into the WebView directly:
// Here using the fetch API as base, but you can use any
// library you want that is able to perform HTTP requests
constructor(props, ctx) {
super(props, ctx);
this.state = { html: null };
}
componentDidMount() {
const data = JSON.stringify({
type: 'car',
plate_number: 'c123'
});
fetch('https://api-stg.caspian.id/user/vehicles/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: '54dc3c3c*******'
},
body: data,
}).then(response => response.text()).then(text => {
this.setState({ html: text });
});
}
render() {
return this.state.html ? (
<WebView
source={{
html: this.state.html,
baseUrl: 'https://api-stg.caspian.id/user/vehicles/add',
}}
originWhitelist={['*']}
/>
) : /* loading UI */ null;
);
Here are the WebView's docs regarding the source property and how to put a static HTML in there:
https://facebook.github.io/react-native/docs/webview#source
You can use a custom extension of WebView, as described in Send Post request along with HttpHeaders on Android (see the duplicate questions for other answers).
I want to call the following webservice as mentioend on this link http://dev.joget.org/community/display/KB/JSON+API#JSONAPI-web%2Fjson%2Fworkflow%2Fprocess%2Flist
So inside my asp.net mvc view i wrote the folloiwng:-
<script type="text/javascript">
$(document).ready(function () {
// Send an AJAX request
$.getJSON("http://localhost:8080/jw/web/json/workflow/process/list?j_username=kermit&hash=9449B5ABCFA9AFDA36B801351ED3DF66&loginAs=admin",
function (data) {
// On success, 'data' contains a list of products.
$.each(data, function (key, val) {
// Format the text to display.
var str = val.id + ': $' + val.packageName;
// Add a list item for the product.
$('<li/>', { text: str })
.appendTo($('#products'));
});
});
});
</script>
<h1>The Processes are</h1>
<ul id="products"/>
But when i run the above web page no processes will be displayed under the <h1>The Processes are </h1> , while if i type the following http://localhost:8080/jw/web/json/workflow/process/list?j_username=kermit&hash=9449B5ABCFA9AFDA36B801351ED3DF66&loginAs=admin directly on the address-bar of my browser then all the processes will be displayed. so what might be going wrong ?
BR
-::::UPDATED::::-
i HAVE UPDATED MY JAVASCRIPT TO BE AS FOLLOW:-
$(document).ready(function(){
$.ajax({
type: "GET",
url: "http://localhost:8080/jw/web/json/workflow/package/list?loginAs=admin",
dataType: "JSONP",
contentType: "application/json; charset=utf-8",
success: function (data) {
$.each(data, function (key, val) {
// Format the text to display.
var str = val.packageId + ': $ ' + val.packageName;
// Add a list item for the product.
$('<li/>', { text: str })
.appendTo($('#products'));
});
}});
});
but the result of the web service call is returned as
undefined: $ undefined
instead of being something such as:-
{"activityId":"","processId":"289_process1"}
So what is the problem that is preventing my code from displaying the right data ?
Try specifying the JSONP callback parameter as callback=? at the end of your query string as explained in the documentation:
var url = 'http://localhost:8080/jw/web/json/workflow/process/list?j_username=kermit&hash=9449B5ABCFA9AFDA36B801351ED3DF66&loginAs=admin&callback=?';
$.getJSON(url, function (data) {
// On success, 'data' contains a list of products.
$.each(data, function (key, val) {
// Format the text to display.
var str = val.id + ': $' + val.packageName;
// Add a list item for the product.
$('<li/>', { text: str }).appendTo('#products');
});
});
UPDATE:
After showing your JSON (at last) the list of products is contained within a data property, so you need to adapt your $.each and operate on this property and not directly on the result:
{
"data": [
{
"packageName": "CRM",
"packageId": "crm"
},
{
"packageName": "EngineersAssociation",
"packageId": "EngineersAssociation"
},
{
"packageName": "LeaveApp",
"packageId": "leaveApp"
},
{
"packageName": "Newtest",
"packageId": "Newtest"
},
{
"packageName": "TestApp",
"packageId": "testapp"
},
{
"packageName": "test54",
"packageId": "test5"
}
]
}
So adapt your code:
var url = 'http://localhost:8080/jw/web/json/workflow/process/list?j_username=kermit&hash=9449B5ABCFA9AFDA36B801351ED3DF66&loginAs=admin&callback=?';
$.getJSON(url, function (result) {
// On success, 'result.data' contains a list of products.
$.each(result.data, function (key, val) {
// Format the text to display.
var str = val.id + ': $' + val.packageName;
// Add a list item for the product.
$('<li/>', { text: str }).appendTo('#products');
});
});
I have written a code to integrate timepicker with editable which is being used to make all coulmns except the hidden id coulmn and the first shown coulmn editable . I couldn't get the fnupdate make my edited coulmn to be updated to the new value when it is posted to server side . I am able to get the posted values for server side processing but the clientside is not gettting updated by fnupdate .
Please see the code below and try to tell me what i am doing wrong because i am having many pages which function the same way .
$(document).ready(function() {
oTable = $('#scheduleTable').dataTable(
{
"sDom" : '<"top"flip>rt<"bottom"<"clear">',
"bAutoWidth" : false,
"bProcessing" : true,
bJQueryUI:true,
"bServerSide": true,
"bFilter":false,
"bSort": false,
"bInfo": false,
"bPaginate":false,
"aoColumns":[
{
"bVisible" : false
},
{
},
{},
{},
{},
{}
],
"fnRowCallback" : function (nRow, aData, iDisplayIndex) {
$(nRow).attr('id', '' + aData[0]);
//i starting from one to make the first element in td non editable
for (i = 1; i < aData.length; i ++) {
$('td:eq(' + i + ') ', nRow).editable("<?= $aupdateUrl; ?>", {
'callback': function (sValue, y) {
var aPos = oTable.fnGetPosition(this);
oTable.fnUpdate(sValue, aPos[0], aPos[1]);
},
"submitdata": function ( value, settings ) {
return {
"row_id": this.parentNode.getAttribute('id'),
"column": oTable.fnGetPosition( this )[2]
};
},
'height': '14px',
indicator : 'Saving...',
tooltip : 'Doubleclick to edit...',
type : "timepicker",
placeholder : ' '
});
}
return nRow;
},
"sAjaxSource" : "<?= $aSourceList; ?>/startdate/<?= $this->startdate; ?>"
}
);
});
$('.ui-datepicker-close').live('click', function (e){
e.preventDefault();
$('#scheduleTable tbody td input').parents("form").submit();
});
$.editable.addInputType('timepicker',{
/*create input element*/
element:function(settings,orginal){
var form = $(this),
input = $('<input type="text">');
form.append(input);
return (input);
},
plugin:function(settings,original){
/*Don't cancel inline editing onblur to allow clicking datepicker*/
settings.onblur = 'nothing';
$("input",this).filter(":text").timepicker(
{ timeFormat: 'hh:mm',
'hourMin':6,
'hourMax':21,
'showSecond': false,
'hourGrid':2,
'minuteGrid':10
}
);
}
});
I was able to solve the problem .The main thing that i was doing wrong was that i didn't have json response with only one value from my server side zend framework action.Therefore it caused the editable to function in a way that it couldn't put the value(the response) as the new value in the td element. Hope some on find it usefull peace!!
My autocomplete is not working and I can't spot the error.
Jquery:
<script>
$(function() {
$('#autoComplete').autocomplete({
//source: "/groceries/items/autoComplete", ///This works but response isn't formatted correctly'
//dataType: "json"
minLength: 2,
source: function( request, response ) {
$.ajax({
url: "/groceries/items/autoComplete",
dataType: "jsonp",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
term: request.term
},
success: function( data ) {
response( $.map( data, function( el ) {
return { label: el.id, value: el.name }
}));
}
});
}
});
});
Controller:
public function autoComplete() {
Configure::write('debug', 0);
$this->layout = 'ajax';
$query = $_GET['term'];
$items = $this->Item->find('all', array(
'conditions' => array('Item.name LIKE' => $query . '%'),
'fields' => array('name', 'id', 'category_id'),
'group' => array('name')));
$this->set('items', $items);
}
Form:
<p>
<?php echo $this->Form->create('Item', array('model'=>'item','action' => 'addItem', 'name'=>'AddItem'));?>
<?php echo $this->Form->text('Item.name', array('size'=>'30', 'id'=>'autoComplete', 'autocomplete'=>'off')); ?>
<?php echo $this->Form->text('Item.category_id', array('type'=>'hidden', 'value'=>'0')); ?>
<?php echo $this->Form->text('Groclist.id', array('type'=>'hidden', 'value'=>$groclist['Groclist']['id'])); ?>
<?php echo $this->Form->end('Add'); ?>
</p>
Response:
0: {Item:{name:Cake, id:6, category_id:null}}
1: {Item:{name:Carrot Cake, id:9, category_id:null}}
2: {Item:{name:Carrots, id:8, category_id:null}}
3: {Item:{name:Casserole, id:11, category_id:null}}
4: {Item:{name:Cauliflower, id:10, category_id:null}}
Edited for clarification.
I realize JqueryUI expects label and value and that map should rearrange them, but for some reason it's not. Any ideas?
I found an even better solution. This is done completely in the controller. No view required.
public function autoComplete() {
Configure::write('debug', 0);
*$this->autoRender=false;*
$this->layout = 'ajax';
$query = $_GET['term'];
$items = $this->Item->find('all', array(
'conditions' => array('Item.name LIKE' => $query . '%'),
'fields' => array('name', 'id', 'category_id'),
'group' => array('name')));
*$i=0;
foreach($items as $item){
$response[$i]['value']="'".$item['Item']['id']."'";
$response[$i]['label']="'".$item['Item']['name']."'";
$i++;
}
echo json_encode($response);*
}
What if you reduce the array that is being returned by the Items model. So instead of $this->set('items', $items); you return the json encoded results like so:
foreach($items as $item) {
$data[] = $item['Item'];
}
$data = json_encode($data);
echo $data;
exit;
This is inside the auto_complete method in the controller.
UPDATE:
When querying for Cake for example, it would return a result like so:
[
{"name":"Cake Batter","id":"1","category_id":"3"},
{"name":"Cake Mix","id":"2","category_id":"3"}
]
if you are not wanting to return the json, you could just return $data without the json encoding.
Format Update:
I am not certain if this is to "sloppy", but you could change the foreach loop to:
foreach($items as $item) {
$data[]= array(
'label' => $item['Item']['name'],
'value' => $item['Item']['id']
);
}
Looks like you forgot the Item:
response($.map( data, function( el ) {
return { label: el.Item.id, value: el.Item.name }
});
You can also do it in the server side using Set:
$this->set('items', Set::extract('/Item', $items));