the last 5 days I fall into despair. I am forced to use an ajax interface for getting usernames in an autocomplete input. This works fine but I also want to add some user-avatars. Adding an avatar-image to autocomplete search results works fine too but only by typing avatar-path directly without ajax response to _renderItem() like
//see complete code below
var inner_html = '<img src="img/avatar-123.png" /><span>' + item.label + '</span>';
I want to manipulate the first ajax JSON-result:
{"data":[{"label": "Simon",
"value":{ "shareType":0,
"shareWith":"Simon"
}
}],
"status":"success"}
in something like this:
{"data":[{ "label": "Simon",
"value":{ "shareType":0,
"shareWith":"Simon"
"avatar":"img/avatar-123.png"
}
}],
"status":"success"}
But adding a new avatar-Object to the json-Object don't work :( Do you have any ideas what I am doing wrong?
$("#search").autocomplete({
minLength: 2,
focus : function(event, focused) {
event.defaultPrevented();
},
source: function(search, response) {
$.when(
//get usernames
$.get(OC.filePath('core', 'ajax', 'share.php'), {
fetch : 'getShareWith',
search : search.term
})
/*example result:
{"data":[{ "label": "Simon",
"value":{ "shareType":0,
"shareWith":"Simon"
}
}],
"status":"success"}*/
//result of first ajax goes in the next round
).then(function(content) {
$.each(content.data, function(i, item) {
//get avatars for usernames
$.get(OC.filePath('ownchat', 'ajax', 'get_avatar.php'), {
username: content.data[i].label
}, function(img) {
//firebug says everthing is working till here
//now I want to add a new avatar-Object to the json-Object
content.data[i].value.avatar = img;
});
});
//the following code-result is empty
//alert(content.data[0].value.avatar);
//but calling
//setTimeout(function(){
// response(content.data);
// },2000);
//in place of the following line, it works sometimes
response(content.data);
});
}/*,
manipulate search result
response: function (e, ui) {
This do not work too :(
for(i in ui.content) {
$.get(OC.filePath('ownchat', 'ajax', 'get_avatar.php'), {
user_id: ui.content[i].label
}, function(img) {
ui.content[i].avatar.push = { avatar: img };
});
}
}*/
}).data("ui-autocomplete")._renderItem = function (ul, item) {
var inner_html = '<img src="'+ item.value.avatar +'" /><span>' + item.label + '</span>';
return $("<li></li>")
.data("item.autocomplete", item)
.append(inner_html)
.appendTo(ul);
};
Sorry for the long text but I hope you can help.
Greetings André
Once i also needed this type of requirement in which username and picture was needed to show, after trying alot, what i came up was build my own custom autocomplete, and it works great i reuse it whenever it is required, you can see it here:
http://developmentpassion.blogspot.com/2013/12/facebook-and-linkedin-like-searching.html
Related
I have a list of items obtained upon querying a database. Result of the query is treated with jsonifyand finally obtained via getJson, by doing the following:
$(function() {
$.getJSON($SCRIPT_ROOT + '/appointments/', function(data) {
var output="<ul>";
for (var i in data.appts) {
output+="<li>" + data.appts[i].labo + "</li>"
}
output+="</ul>";
$("#result").html(output)
return false;
});
});
So far so good...
Now I need to give the possibility to delete each of the above listed items, by calling (for example ) the following Flaskfunction:
#app.route('/appointments/<int:appointment_id>/delete/', methods=['DELETE'])
def appointment_delete(appointment_id):
appt = db.session.query(Appointment).get(appointment_id)
db.session.delete(appt)
db.session.commit()
return jsonify({'status': 'OK'})
Unfortunately I have no clue on how it's possible to bridge these two pieces of code. Since I've being struggling on that for a while, I would appreciate any help that will allow me to get out of the mud... Thanks a lot.!
EDIT according to #dcodesmith's comment
The getJSON response:
{
"appts":[
{
"id":1,
"day":"Mardi",
"labo":"l1",
"modified":[
"21/01/2014"
],
"groups":"5",
"plage_h":"10h00",
"sem":"5",
"start":[
"28/01/2014"
]
},
{
"id":4,
"day":"Vendredi",
"labo":"l1",
"modified":[
"22/01/2014"
],
"groups":"5",
"plage_h":"10h00",
"sem":"5",
"start":[
"31/01/2014"
]
}
]
}
Changes required
Firstly, edit your output HTML to include an anchor tag which should have a data-id attribute with the appts id assigned to it.
Create a click event on the anchor tag in your list of appts
Code
$(function() {
$.getJSON($SCRIPT_ROOT + '/appointments/', function(data) {
var output = "<ul>";
for (var i in data.appts) {
var appt = data.appts[i];
output += "<li>" + appt.labo + "delete</li>"
}
output+="</ul>";
$("#result").html(output)
return false;
});
$(document).on('click', 'a.delete', deleteAppt);
function deleteAppt(e){
e.preventDefault();
var $this = $(this),
id = $this.data('id'),
url = "/appointments/" + id + "/delete/";
$.ajax({
url: url,
type: 'POST',
data: {id: id}
})
.done(function(data, textStatus, jqXHR){
if (data.status === 'OK'){
// if successful remove deleted row
$this.parent('li').remove();
}
})
.fail(function(jqXHR, textStatus, errorThrown){
//log your error here, if any is caught. This will be very helpful for debugging
})
}
});
Note: I know nothing about Flask, but this should work Ceteris Paribus
Perhaps I'm not understanding this concept (I'm an AJAX/javascript/Web newbie). I'm using the JQuery autocomplete feature and if I specify a small, limited items flat file (suggestions.xml) the function works fine, but when I use an actual production data file (3 MB) of suggestions the script doesn't work at all.
So I created a web service that generates XML based on the characters in the textbox but it appears this JQuery doesn't run on each keypress, rather only when the page first loads. Obviously, for this function to be of any use it needs to fetch results dynamically as the user types into the input field.
$(document).ready(function () {
var myArr = [];
$.ajax({
type: "GET",
// this line always sends the default text; not what the user is typing
url: "Suggestions.aspx?searchString=" + $("input#txtSearch").val(),
dataType: "xml",
success: parseXml,
complete: setupAC,
failure: function (data) {
alert("XML File could not be found");
}
});
function parseXml(xml) {
//find every query value
$(xml).find("result").each(function () {
myArr.push({ url: $(this).attr("url"), label: $(this).attr("name") + ' (' + $(this).attr("type").toLowerCase() + ')' });
});
}
function setupAC() {
$("input#txtSearch").autocomplete({
source: myArr,
minLength: 3,
select: function (event, ui) {
$("input#txtSearch").val(ui.item.label);
window.location.href = ui.item.url;
//alert(ui.item.url + " - " + ui.item.label);
}
});
}
});
On the server I expected to see a few requests corresponding to the characters the user is typing into the search box but instead I get a single message:
2013-10-18 22:02:04,588 [11] DEBUG baileysoft.mp3cms.Site - QueryString params: [searchString]:'Search'
My flat file of suggestions appears to be way to large for JQuery to handle and my web service script is never called, except when the page is first loaded.
How do I generate suggestions dynamically as the user is typing in the search box if I can't run back to the database (via my web service) to fetch suggestions as the user is typing?
Ok, I got it all worked out.
On the ASPNET side; I created a form to receive and respond to the AJAX:
Response.ContentType = "application/json";
var term = Request.Form["term"];
var suggestions = GetSuggestions(term); // Database results
if (suggestions.Count < 1)
return;
var serializer = new JavaScriptSerializer();
Response.Write(serializer.Serialize(suggestions);
On the AJAX side I modified the js function:
$("input#txtSearch").autocomplete({
minLength: 3,
source: function (request, response) {
$.ajax({
url: "Suggestions.aspx",
data: { term: $("input#txtSearch").val() },
dataType: "json",
type: "POST",
success: function (data) {
response($.map(data, function (obj) {
return {
label: obj.Name,
value: obj.Url
};
}));
}
});
},
select: function (event, ui) {
$("input#txtSearch").val(ui.item.label);
window.location.href = ui.item.value;
}
});
Everything is working as expected now.
Hope this helps someone else who might get stuck trying to figure out JQuery stuff for ASPNET.
I want to send json data from my controller to my view when a specific action happens.
I used this on controller to send the data
[HttpGet]
public JsonResult JSONGetParking(int buildingID){
return this.Json(
new
{
Result = (from obj in db.Parkings.Where(p => p.buildingID == buildingID) select new { ID = obj.ID, Name = obj.note })
}
, JsonRequestBehavior.AllowGet
);
}
it works very good
on my script i used this:
FloorScript.js
$(document).ready(function () {
$('#buildingID').change(function () {
alert("what is not");
$.getJSON('JSONGetParking?buildingID=' + $('#buildingID').val(), function (data) {
alert("afd");
var items = " ";
$.each(data, function (obx, oby) {
items += "<option value='" + oby.ID + "'>" + oby.Name + "</option>";
});
$('#parkingID').html(items);
});
});
});
I have opened google chrome and I can see the request and the response like this:
i can see the two text that i alerted
However, on my selector, i just see undefined value
Html
<div id="editor-label">
<select id="parkingID" name="parkingID"></select>
</div>
I have added the jquery in this
#section scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/Scripts/FloorScript.js");
}
You're not looping on the correct variable.
You did this:
$.each(data, function (obx, oby) {
whereas you should do this:
$.each(data.Result, function (obx, oby) {
This is pretty visible in the Google Chrome screenshot you provided. As you can see the returned JSON has a property called Result which is the collection whereas you were looping over the data variable which is not an array - it's just a javascript object that has a property called Result which is the array you wanna be looping through.
Also I'd replace:
$.getJSON('JSONGetParking?buildingID=' + $('#buildingID').val(), function (data) {
with:
$.getJSON('JSONGetParking', { buildingID: $('#buildingID').val() }, function (data) {
and of course get rid of this hardcoded url over there and use an url helper to generate it, on the dropdown as an HTML5 data-* attribute:
#Html.DropDownListFor(
x => x.BuildingId,
Model.Buildings,
new {
id = "buildingID",
data_url = Url.Action("JSONGetParking")
}
)
and then inside the change event you can trivially easy retrieve this url and avoid hardcoding it (and of course taking the risk of breaking your code when you deploy it in IIS in a virtual directory or simply change the routing pattern of your application):
$('#buildingID').change(function () {
var url = $(this).data('url');
$.getJSON(url, { buildingID: $('#buildingID').val() }, function (data) {
Alright, now the initial mess is tidied up.
use data.Result in your each loop
$(document).ready(function () {
$('#buildingID').change(function () {
alert("what is not");
$.getJSON('JSONGetParking?buildingID=' + $('#buildingID').val(), function (data) {
alert("afd");
var items = " ";
$.each(data.Result, function (obx, oby) {
items += "<option value='" + oby.ID + "'>" + oby.Name + "</option>";
});
$('#parkingID').html(items);
});
});
});
Hope this helps...
Here is the code I'm attempting to use (parts pulled from remote json, parts removed from the custom data display):
$(function () {
$("#Field1Text").autocomplete({
minLength: 0,
source: function (request, response) {
$.ajax({
url: "/Main/Users/GetItems",
dataType: "json",
data: {
group: "Default",
query: request.term
}
},
focus: function (event, ui) {
$("#Field1Text").val(ui.item.Description);
return false;
},
select: function (event, ui) {
$("#Field1Text").val(ui.item.Description);
return false;
}
})
.data("autocomplete")._renderItem = function (ul, item) {
return $("<li>")
.data("item.autocomplete", item)
.append("<a><strong>" + item.Description + "</strong><br>" + item.Section + " - " + item.Type + " - " + item.Name + "</a>")
.appendTo(ul);
};
});
The data pulls back fine, but the render item function never fires. I've scrapped the render item version and used success: inside of source and it looked like this:
success: function (data) {
response($.map(data, function (ul, item) {
return $("<li>")
.data("item.autocomplete", item)
.append("<a><strong>" + item.Description + "</strong><br>" + item.Section + " - " + item.Type + " - " + item.Name + "</a>")
.appendTo(ul);
}));
}
I used firebug and I was able to hit a breakpoint at the response section: if I looked at the data in data, it looked like:
[ Object { ...data... }, Object { ...data... }]
If I set a breakpoint at the .data line of the success section, I see that ul is one of the objects ( looks like " Object { ... data ... }")
the item element is 0 at this point, and when I attempt to render the <a> tags, it comes out as Undefined on all of the properties (understandable, looks to be treating the item object as an int).
How do I get that component to handle properly?
edit: sorry, I wanted to add a jsFiddle per the suggestion in the comments but had family stuff going on.
http://jsfiddle.net/EYj8v/2/
I commented the code that is similar to what we use at work. Unfortunately, the web app is an internal one with a database that isn't connected to the outside world so I can't use live data. The testResults object is what I saw in the success: section's data element.
I was actually able to get the success section to fire, but I don't believe I'm using jQuery UI/Autocomplete correctly (at least my assumptions) as I was able to look at ul.Properties and see real data. Appending the items worked with bogus data, but when I attempted to copy and paste the success block into the render item, all of the data was undefined. Nor could I find a one-to-one mapping at that stage (ul was the element on the page, item was just [li]).
I have two textboxes (input type text) on the same HTML that use the same autocomplete. The first text box works fine, but the second text box do not render the results. It communicate with the server and I get the results, but the rendering function is not even called. The only difference between the inputs is that one is in a div that start hidden and I show kind like Dialog window by setting z-order high and masking the HTML.
Here is the CSS for the div where the second input box is located.
.windowBooking {
position:absolute;
width:450px;
/* height:200px; */
display:none;
z-index:9999;
padding:20px;
}
The autocomplete function:
$(".makeClass").autocomplete({
source: function (request, response) {
$('#Code').val(); //clear code value
$.ajax({
url: "myUrl",
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json', //What kind of Result is expected. (Ex json, xml, etc)
data: "{'searchItem':'" + request.term + "'}",
success: function (data) {
var item = [];
var len = data.d.length;
for (var i = 0; i < len; i++) {
var obj = { name: data.d[i].MakeReport, code: data.d[i].MakeCode };
item.push(obj);
}
response(item);
}
})
},
focus: function (event, ui) {
$(this).val(ui.item.name);
return false;
},
select: function (event, ui) {
$('#Code').val(ui.item.code);
$('#Name').val(ui.item.name);
$(this).val(ui.item.name);
return false;
},
open: function () {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function () {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
},
minLength: 2,
delay: 250
}).data("autocomplete")._renderItem = function (ul, item) {
var temp = item.name;
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.name + "</a>")
.appendTo(ul);
};
The input boxes use the same class to call the autocomplete.
<input id="OtherMake" type="text" maxlength="30" size="20" class="makeClass"/> <!-- It works -->
<div id="dialogPlus" class="windowBooking">
:
<input type="text" id="MakeName" class="makeClass" /> <!-- doesn't work.-->
:
</div>
Any ideas, why render on one input box and no in the other input box? Let me make clear, on the second input box the only thing not working is the renderItem function which for some reason it doesn't get executed. On the screen, you can see a lot of undefined but if you select any of the undefined values then the input box is filled with the correct value.
I had a similar issue applying _renderItem() on a class selector but solved it with
$.each($( ".makeClass" ), function(index, item) {
$(item).data("autocomplete")._renderItem = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.value + " - " + item.label + "</a>")
.appendTo(ul);
};
});
I still don't know what is causing the problem, but I was able to make it work by using the ID instead of using a class to access autocomplete. My guess is that an appended render function cannot be shared between two input boxes? I don't know, if somebody knows the answer and could share with us, it would be great.
Anyway, if somebody happen to have the same weird problem as me and it is stuck with the problem, here is how I solved it. As, I didn't want to repeat the same code twice, I moved all the autocomplete logic to a var and the render function to another var and used the input box ID to assign autocomplete.
var makeAutocomplete = {
source: function (request, response) {
$('#Code').val(); //clear code value
$.ajax({
url: myUrl,
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json', //What kind of Result is expected. (Ex json, xml, etc)
data: "{'searchItem':'" + request.term + "'}",
success: function (data) {
var item = [];
var len = data.d.length;
for (var i = 0; i < len; i++) {
var obj = { name: data.d[i].MakeReport, code: data.d[i].MakeCode };
item.push(obj);
}
response(item);
}
})
},
focus: function (event, ui) {
$(this).val(ui.item.name);
return false;
},
select: function (event, ui) {
$('#Code').val(ui.item.code);
$('#Name').val(ui.item.name);
$(this).val(ui.item.name);
return false;
},
open: function () {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function () {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
},
minLength: 2,
delay: 250
};
var renderList = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.name + "</a>")
.appendTo(ul);
};
$("#OtherMake").autocomplete(makeAutocomplete).data("autocomplete")._renderItem = renderList;
$("#MakeName").autocomplete(makeAutocomplete).data("autocomplete")._renderItem = renderList;
I have this bug too. This is strange that with id as selector _renderItem works correct. I found a quick hack for this issue:
$.ui.autocomplete.prototype._renderItem = function (ul, item) {}
For me, what fixed it was using the appendTo option from the jQuery UI AutoComplete.
My problem was that this input field was inside a modal that wasn't shown at first. Affecting it to the input's parent fixed the problem!