0

I’m wondering if anyone can help me.

I’m attempting to create a search box for my MVC application that autocompletes (makes suggestions on the basis of the user's input) with images instead of text.

The feature will check whether the user’s input is similar to a “Title” property from an Entity Framework database table called “Word” and then return it’s “Imagepath” property, which is a string path to the image.

This path should then be used in the View to return a list of relevant images auto completing the user's query. These images are then clickable and link to their respective pages.

Similar to the below but without the text and solely box images:

https://www.algolia.com/doc/assets/images/guides/search-ui/autocomplete-textarea-8-2565ba67.png

I am struggling with the code here as I am unfamiliar with the Ajax and Javascript that I understand is necessary to achieve this in real time.

My attempt is outlined below:

  1. DATABASE MODEL: The table is essentially this:

    public class Word
        {
          public int Id { get; set; }
          public string Title { get; set; }
          public string Imagepath { get; set; }
        }
    
  2. CONTROLLER: _context is the database. Controller name is "WordsController".

    [HttpPost]
    public JsonResult AutoComplete(string Prefix)
    {
        var words= _context.Words.ToList();
    
        var specifiedWords = (from w in words
                              where w.Title.StartsWith(Prefix) || w.Title.Contains(Prefix)
                             select new { w.Imagepath });
    
        return Json(specifiedWords , JsonRequestBehavior.AllowGet);
    }
    
  3. VIEW: Firstly here is my attempt at the Javascript. I am trying to return a list of "Words" from the "Words" Controller above and append their Imagepath property to an HTML element attempting to create a sort of list. The search box and css is below.

    <script src="~/Scripts/jquery-3.2.1.js"></script>
    <script src="~/Scripts/jquery.validate.js"></script>
    <link rel= "stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" > 
    <script src="//code.jquery.com/jquery-1.10.2.js"></script>
    <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
    
    <script>
    $(document).ready(function () {
    $("#Title").autocomplete(
    {
        source: function (request, response) {
            $.ajax({
                url: "/Words/AutoComplete",
                type: "POST",
                dataType: "json",
                data: { Prefix: request.term },
                success: function (data) {
                    response($.map(data, function (item) {
                        return {
                            label: item.Imagepath,
                            value: item.Title
                        };
                    }));
                }
            });
        },
        open: (event) => {
            $('.ui-autocomplete .ui-menu-item div').toArray().forEach((element) => {
                let imagePath = element.innerHTML;
                $(element).html('');
                var inner_html = '<div class="list_item_container"><div class="image"><img src="' +
                    imagePath + '"></div>';
                $(element).append(inner_html);
            });
        }
    });
    });
     </script>
    

Searchbox:

@Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } }) 

CSS:

<style>
.list_item_container {
    width: 300px;
    height: 60px;
    padding: 5px 0;
}

.image {
    width: 60px;
    height: 60px;
    margin-right: 10px;
    float: left;
}

Needless to say, my best attempts do not yet work.

The JavaScript has been loosely taken from the tutorial here (which only covers autocompletion with words:

http://www.jamiemaguire.net/index.php/2017/04/08/how-to-implement-an-autocomplete-control-with-asp-net-mvc-and-json/

Any pointers or links to useful resources would be massively appreciated. Thanks!

Scribbio
  • 113
  • 10

1 Answers1

1
  1. set open. open trigger after response has been received and content has been rendered.

                {
                source: function(request, response) {
                    $.ajax({
                        url: '@Url.Action("AutoComplete", "Words")',
                        type: "POST",
                        dataType: "json",
                        data: { Prefix: request.term },
                        success: function (data)
                        {
                            response($.map(data, function (item)
                            {
                                return {
                                    label: item.Imagepath,
                                    value: item.Title
                                       }
                            }));
                        }
                    });
                },
                open: (event) => {
                    $('.ui-autocomplete .ui-menu-item div').toArray().forEach((element) => {
                        let imagePath = element.innerHTML;
                        $(element).html('');
                        var inner_html = '<div class="list_item_container"><div class="image"><img src="' +
                            imagePath + '"></div>';
                        $(element).append(inner_html);
                    });
                }
            }
    
  2. in case if autocomplete function is not defined or can't be called the following link will be useful .autocomplete is not a function Error

  3. i guess you forgot to return title as well:

     var specifiedWords = (from w in words
            where w.Title.StartsWith(Prefix) || w.Title.Contains(Prefix)
            select new { w.Imagepath, w.Title });
    
        return Json(specifiedWords, JsonRequestBehavior.AllowGet);
    
Z.R.T.
  • 1,543
  • 12
  • 15
  • Ok! I think we're getting close and the list is working. However, the inner HTML doesn't append properly and I receive a list of strings instead of images. Are you still able me to discern what is wrong? Thanks. – Scribbio Dec 18 '17 at 01:44
  • you use exactly same js script as i posted or another one ? if another , then could you post it – Z.R.T. Dec 18 '17 at 02:23
  • The same as yours. – Scribbio Dec 18 '17 at 02:46
  • could you update your code , it would be easier for me . also interesting with js libs you using – Z.R.T. Dec 18 '17 at 02:56
  • Sure thing, I've updated my code and included the relevant scripts. The first two Jquery scripts are actually contained in a bundle but I've put them in script form for easy future reference. – Scribbio Dec 18 '17 at 03:16
  • the issue with lib, if you use **//code.jquery.com/ui/1.11.4/jquery-ui.js** it render **ul > li** only. in new versions like **jquery-ui-1.12.1.js** it render as **ul > li > div**. you just need to edit this line $('.ui-autocomplete .ui-menu-item').toArray().forEach((element) => { – Z.R.T. Dec 18 '17 at 03:36
  • one more thing, return { label: item.Imagepath, value: item.Title }, **value: item.Title ** the one which is displayed in the box after click on list element. in your case you dont get Title from server – Z.R.T. Dec 18 '17 at 04:02
  • Will do, html is working now, however, images won't display as they're saved as "~//Images//Image.png in the database. Works fine if I render the image directly in the View and not through javascript, I'm currently searching a solution for this too unless you could help me yet again? :) – Scribbio Dec 18 '17 at 04:33
  • save image as /Images//Image.png, without ~ – Z.R.T. Dec 18 '17 at 04:47
  • I can't remove the tilde as my application depends on relative paths. Any suggestion on developing a function to clear up the path? Such as using imagePath.substring(2);? – Scribbio Dec 18 '17 at 16:14
  • OK! using .substring() works! Can't thank you more for your help. As a final note, do you know how I could set a limit to the number of images dropping now? – Scribbio Dec 18 '17 at 16:21