codeigniter jquery autocomplete - jquery-ui

Why doesn't the list auto update as I type? No matter what I type the list is the same.
I would like to be able to type "wj" and it will only list items starting with "wj".
JS
$(function()
{
$("#part_num_id").autocomplete({
source: "partnum/get"
});
});
Controller
public function get()
{
$q = $this->input->post('term', TRUE);
$this->load->model('partnum_model');
$this->partnum_model->get_partnum2($q);
}
Model
function get_partnum2($q)
{
$this->db->select('*');
$this->db->like('part_num', $q);
$query = $this->db->get('item_history');
if($query->num_rows > 0)
{
foreach ($query->result_array() as $row)
{
$new_row['label']=htmlentities(stripslashes($row['part_num']));
$new_row['value']=htmlentities(stripslashes($row['id']));
$row_set[] = $new_row; //build an array
}
echo json_encode($row_set);
}
}

I may be wrong since I haven't thoroughly tested this,
but I believe the autocomplete sends a GET request, not a POST request.
Therefore
$q = $this->input->post('term', TRUE);
won't bring you anything; Instead you should write
$q = $this->input->get('term', TRUE);

Related

Kendo Upload control remove event has no response

I have a kendo upload control like this:
#(Html.Kendo().Upload()
.Name("attachments")
.Async(a => a
.Save("UploadAsync", "Intel")
.Remove("RemoveAsync", "Intel")
.AutoUpload(true)
)
.Events(e => e
.Success("onSuccessfulUpload")
.Remove("onRemoveFile")
)
.Validation(v => v.AllowedExtensions(exts))
)
In the controller, its Save method is like this:
public ActionResult UploadAsync(IEnumerable<HttpPostedFileBase> attachments)
{
string filename;
// ... do things ...
return Json(new { ImageName = filename }, "text/plain");
}
where the variable filename is assigned a value.
Its Remove method in the controller looks very similar:
public ActionResult RemoveAsync(string[] fileNames)
{
string filename;
// ... do things ...
return Json(new { ImageName = filename }, "text/plain");
}
I verified that both controller methods are called correctly and the variable filename is assigned to in both cases.
The upload works as expected, and the Success event also works as expected. (The alert is simply for testing.)
function onSuccessfulUpload(e) {
alert(e.response.ImageName);
}
The issue comes on removal of a file.
When I get to the Remove event, e does not have a .response. It has e.files and e.sender, but no response.
function onRemoveFile(e) {
alert(e.response); // undefined!
alert(JSON.stringify(e.files)); // works, but does not have what I need
}
How do I access what the RemoveAsync method returns?
It looks like the remove event doesn't provide this kind of data, so I see only a workaround to solve this.
You could try to put the result name to the headers, and you should be able to read the result:
// Controller
Response.AddHeader("ImageName", imageName); // before Json(...)
// View/JS
alert(e.headers['ImageName']);
I haven't tested that and I see a risk that that the remove event doesn't really read the async response, that would explain why the response object is not available.
In that case, you could try to use the following workaround: Don't call any Url on remove (or use some Action without any body, just a plain result) and inside of the event callback, execute RemoveAsync yourself.
// View/JS
function onRemoveFile(e) {
$.post('#Html.Url("RemoveAsync", "Intel")', e.files, function(response) {
alert(response);
});
}
It's not pretty, but it should work and provide the results you need.
After some time poking around, I found the answer.
The key lay in the order of the events. My first assumption was that the Success event was called after successful upload, and the Remove event was called after successful(?) removal. This was wrong.
The actual order of the events is:
JS onUpload > Controller UploadAsync > JS onSuccess
JS onRemoveFile > Controller RemoveAsync > JS onSuccess
My Solution:
I created two parallel arrays in javascript to represent the files uploaded in the client-side e.files, which contains uid's for each file, and the filenames created by the server-side controller method (which renames the files).
var fileUids = [];
var fileSaveNames = [];
I changed the onSuccessfulUpload function to this, when I discovered that there is an e.operation that specifies which operation was the successful one:
function onSuccess(e) {
if (e.operation == "upload") {
var filename = e.response.ImageName;
var uid = e.files[0].uid;
// add to the arrays
fileUids.push(uid);
fileSaveNames.push(filename)
// ...
}
else if (e.operation == "remove") {
var uid = e.files[0].uid;
var saveIdx = fileUids.indexOf(uid);
// remove from the arrays
fileSaveNames.splice(saveIdx, 1);
fileUids.splice(saveIdx, 1);
// ...
}
}
Then I updated the removeFile function, which I now knew was called before the method in the controller.
function removeFile(e) {
var uid = e.files[0].uid;
var idx = fileUids.indexOf(uid);
e.data = { fileToRemove: fileSaveNames[idx] };
}
That last line, where I assign to e.data, was because of this thread on the Telerik forums, which has the following info:
Solution: All that's needed it to define a function for the upload
event and modify the "data" payload.
Add the upload JS function to add a parameter "codeID" in my case.
$("#files").kendoUpload({
[...]
upload: function (e) {
e.data = { codeID: $("#id").val() };
}
});
Now on the controller add the parameter and that's it.
[HttpPost]
public ActionResult Save(IEnumerable<HttpPostedFileBase> files, Guid codeID) { }
(Instead of being in the Upload event, mine is in the Remove event.)
I chose the parameter name fileToRemove, and now the new RemoveAsync method in the controller is as such:
public ActionResult RemoveAsync(string[] fileNames, string fileToRemove)
{
string returnName = "";
if (!string.IsNullOrWhiteSpace(fileToRemove))
{
// ... do things ...
}
return Json(new { ImageName = returnName }, "text/plain");
}

How do you test what elements a jquery-ui sortable element is connected to?

I would like test what jquery-ui sortable elements are connected. Is this information stored somewhere, or is there some way to figure it out?
For example if I have four lists, and I want to see if any of them are connect and if so which list they are connected to how would I do that?
Here's a code example:
https://jsfiddle.net/mL1e0mLh/
$('#sortable1').sortable({ connectWith: '#sortable4' });
$('#sortable2').sortable();
$('#sortable3').sortable();
$('#sortable4').sortable({ connectWith: '#sortable1' });
function getConnectedList(element) {
var connectedElement = null;
// Do something
return connectedElement;
}
getConnectedList(document.getElementById('sortable1')); // Should return element with ID #sortable4
getConnectedList(document.getElementById('sortable2')); // Should return null
getConnectedList(document.getElementById('sortable3')); // Should return null
getConnectedList(document.getElementById('sortable4')); // Should return element with ID #sortable1
You can use the instance method to do this:
function getConnectedList(element) {
return element.sortable( "instance" ).options.connectWith;
}
jsFiddle example

ajax request php class function

i have content listed in a div and i have a dropdown with various options to order and filter that content.
I'm using ajax to filter/order that content and is working but i use other php page with the content i want on the div that has the content, like this
function order(str){
$.post("order_products.php",
{
q: str,
},
function(data, status){
document.getElementById("txtHint").innerHTML = data;
});
}
What i wanted was to instead of putting the code (data) to change in another page just for that, i could put that code inside a class php function that i have.
<?php
class products{
function list(){
blablabla
}
That way i would "save space" and organize everything, considering that i have many other things to order/filter but i don't know to to make the ajax request to that function, or if it's possible without having a page in between and then get the response from the function and put it on the div.
You can do this using Laravel by setting up a route to a function that will do the ordering. Please note I've made a lot of assumptions in the following answer as I can't see all your code and have made it quite general, please adjust the code to your project or provide more details of your code if you don't understand the answer fully.
routes.php
Route::post('products/order', [
'as' => 'products.order',
'uses' => 'ProductsController#orderProducts'
]);
Your view (assuming you're using blade)
$txtHint = $('#txtHint'); // grab the reference to txtHint dropdown
$.post( '{{ route("products.order") }}', // hit our route
{
q: str,
},
function(data, status){
$txtHint.empty(); // clear the dropdown
// loop through the data and assign each element to the dropdown
$.each(data, function(value, key) {
$txtHint.append($("<option></option>")
.attr("value", value)
.text(key));
});
});
ProductsController.php
public function orderProducts()
{
$orderBy = \Input::get('q');
return \Products::lists('name', 'id')->orderBy($orderBy);
}
For outside of a framework just change the url to your php file and add in a data attribute for the method you require to be fired from the file.
$.post( 'products.php', // hit our route
{
action: 'order',
q: str,
},
...
Then in products.php you'd do something like this
if(isset($_POST['action']) && !empty($_POST['action'])) {
$action = $_POST['action'];
switch($action) {
case 'order' : order();break;
case 'otherFunction' : otherFunction();break;
}
}
function order()
{
// order logic here
// get $_POST['q']
// do your ordering
// return data as json
}
See here for similar question: using jquery $.ajax to call a PHP function

Retrieving a record with breeze

I develop an application with asp.net mvc + breeze.
So far, I retrieve a specific record (based on id) like this:
var getTransportById = function (transportId, transportObservable) {
return manager.fetchEntityByKey('Transport', transportId, true)
.then(fetchSucceeded)
.fail(queryFailed);
}
function fetchSucceeded(data) {
var s = data.entity;
return ...
}
Now I need to retrieve the same record but need to 'expand' the property named sender which links to another entity (table). I did not find a way to 'expand' one property through fetchEntityByKey so I used a query like this:
var getTransportById = function (transportId, transportObservable) {
var query = EntityQuery.from('Transports')
.where('id', 'eq', transportId)
.expand('Sender')
.orderBy(orderBy.transport);
return manager.executeQuery(query)
.then(fetchSucceeded)
.fail(queryFailed);
}
function fetchSucceeded(data) {
var s = data.results[0];
return ...
}
My question: is it the good way to proceed? Is there another way of doing?
Thanks.
You can create a query from an EntityKey and then expand whichever properties you want. Something like this:
var entityKey = new EntityKey("Transport", transportId);
// expand whichever nav props you want here.
var query = EntityQuery.fromEntityKey(entityKey).expand("Sender").orderBy(...);
return entityManager.executeQuery(query).then( {
...
});

jQuery extend of jQuery UI autocomplete

I am trying to extend the default jQuery UI 1.8.16 autocomplete plugin to do a few things:
Check an array of values and not just the label/value when searching for a match
Render the menu item in a different pattern based on a category on the item
So to do this I began to work through the code. I am very new to writing a widget/plugin and so I am wondering if someone can help me understand this part. I am currently trying to do the following:
$.widget("custom.advautocomplete", $.ui.autocomplete, {
filter: function (array, term) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");
return $.grep(array, function (value) {
return matcher.test(value.label || value.alldata || value);
});
},
_renderMenu: function (ul, items) {
var self = this,
currentCat = "";
$.each(items, function (index, item) {
if (currentCat != item.category) {
ul.append("<li class='ui-autocomplete-category'>" + item.category + "</li>");
currentCat = item.category;
}
self._renderItem(ul, item);
});
},
_renderItem: function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append($("<a></a>").text(item.alldata))
.appendTo(ul);
}
});
The _renderMenu code is pretty much taken directly from the example in the documentation. The _renderItem code is working in this example as well. What is not working is the filter code. I did notice that the filter code is defined in the jQuery library like so:
$.extend($.ui.autocomplete, {
escapeRegex: function (value) {
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
},
filter: function (array, term) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");
return $.grep(array, function (value) {
return matcher.test(value.label || value.value || value);
});
}
});
From what I've gathered so far, this is extending the jQuery autocomplete which is defined earlier by a call to $.widget("ui.autocomplete"... But why is this handled this way? Why are these two functions not handled inside the widget definition like everything else? I noticed that if I extend ui.autocomplete in the same manner as it is done by the base widget, then I can get the filter override to work. I would like to extend the control and include the new filter at the same time so I can keep my code a bit cleaner but I don't understand why it is being done like this. Is there a benefit that I'm missing?

Resources