Dynamically pull dojo combo box options from rest api - javascript

I'm looking to dynamically populate a dojo combobox with values that come from a json rest api. Ideally, the user inputs their string into the combo box, a 'get' call is made returning related strings, and the select options are populated with these results.
The JsonRest store seems like a good way to go about doing this, but so far my attempts have been unsuccessful. I am encountering two issues:
My rest api returns a list of strings, while the combo button is expecting a list of objects with specified keys to use as the names/values. I don't have access to the api so I can't change the response structure. -Fixed
The 'get' calls that the json rest store is making is adding an asterisk on to the end of the query, which isn't desirable. -Fixed
My setup looks like this:
this.testStore = new JsonRestStore({
target: "myUrl",
allowNoTrailingSlash: true
});
this.dapComboBox.set('store', this.testStore);
this.dapComboBox.set('searchAttr', 'tag');
Update 1
I've figured out the asterisk issue, it was fixed by setting the combo box's 'queryExpr' attribute to '${0}'
Update 2
I solved the unusable list issue by creating my own basic store with get, getIdentity, and query functions. In my new query function I returned a new deferred object. I processed the returned values from the get request to fit the proper format and resolved this new list with my new deferred.

Issue 1: Fixed by setting the combo box's 'queryExpr' attribute to '${0}'
Issue 2: Created my own basic store with get, getIdentity, and query functions to fix. In my new query function I returned a new deferred object. I processed the returned values from the get request to fit the proper format and resolved this new list with my new deferred.

Related

Parse.com relations count

I want to query object from Parse DB through javascript, that has only 1 of some specific relation object. How can this criteria be achieved?
So I tried something like this, the equalTo() acts as a "contains" and it's not what I'm looking for, my code so far, which doesn't work:
var query = new Parse.Query("Item");
query.equalTo("relatedItems", someItem);
query.lessThan("relatedItems", 2);
It seems Parse do not provide a easy way to do this.
Without any other fields, if you know all the items then you could do the following:
var innerQuery = new Parse.Query('Item');
innerQuery.containedIn('relatedItems', [all items except someItem]);
var query = new Parse.Query('Item');
query.equalTo('relatedItems', someItem);
query.doesNotMatchKeyInQuery('objectId', 'objectId', innerQuery);
...
Otherwise, you might need to get all records and do filtering.
Update
Because of the data type relation, there are no ways to include the relation content into the results, you need to do another query to get the relation content.
The workaround might add a itemCount column and keep it updated whenever the item relation is modified and do:
query.equalTo('relatedItems', someItem);
query.equalTo('itemCount', 1);
There are a couple of ways you could do this.
I'm working on a project now where I have cells composed of users.
I currently have an afterSave trigger that does this:
const count = await cell.relation("members").query().count();
cell.put("memberCount",count);
This works pretty well.
There are other ways that I've considered in theory, but I've not used
them yet.
The right way would be to hack the ability to use select with dot
notation to grab a virtual field called relatedItems.length in the
query, but that would probably only work for me because I use PostGres
... mongo seems to be extremely limited in its ability to do this sort
of thing, which is why I would never make a database out of blobs of
json in the first place.
You could do a similar thing with an afterFind trigger. I'm experimenting with that now. I'm not sure if it will confuse
parse to get an attribute back which does not exist in its schema, but
I'll find out, by the end of today. I have found that if I jam an artificial attribute into the objects in the trigger, they are returned
along with the other data. What I'm not sure about is whether Parse will decide that the object is dirty, or, worse, decide that I'm creating a new attribute and store it to the database ... which could be filtered out with a beforeSave trigger, but not until after the data had all been sent to the cloud.
There is also a place where i had to do several queries from several
tables, and would have ended up with a lot of redundant data. So I wrote a cloud function which did the queries, and then returned a couple of lists of objects, and a few lists of objectId strings which
served as indexes. This worked pretty well for me. And tracking the
last load time and sending it back when I needed up update my data allowed me to limit myself to objects which had changed since my last query.

Knockout - Updating observableArray in View Model

I wish to save my view model to a database as a JSON string. The idea is that I can then re-load my view model by reading the JSON back and using the direct approach to load my view model's data:
From the Knockout documentation:
// Load and parse the JSON
var someJSON = /* Omitted: fetch it from the server however you want */;
var parsed = JSON.parse(someJSON);
// Update view model properties
viewModel.firstName(parsed.firstName);
viewModel.pets(parsed.pets);
That all works great but where I've already initialised my model and I'm simply updating it with one that I've already saved, I can't see how I can select the originally selected entry in the array's drop-down list.
To put it another way, the pets drop-down list is selected as "Cat" when I save my model. I then change the drop-down list selection to "Dog". On re-loading the saved model, I need my drop-down list selection to be reset to "Cat".
I'm a bit concerned about this because I have some arrays of objects which also need to be read in from the saved model and it's looking like it's going to be very difficult to do.
Any ideas or suggestions are welcome :)
What you are looking for is the mapping plugin for Knockout. http://knockoutjs.com/documentation/plugins-mapping.html
It has methods that handle both JSON to observables and back.
So in your example you could do:
var viewModel = ko.mapping.fromJSON(someJSON);
And when you're ready to go back to the server:
var jsonData = ko.mapping.toJSON(viewModel);
There are also object literal helpers if you need that (ko.mapping.toJS & ko.mapping.fromJS)

KnockoutJS: Update/Insert data to a viewModel using mapping

I've been trying to figure this out for quite some time now. I couldn't find anything that addresses this problem, but please correct me if I'm wrong.
The problem:
I have data from a JSON API comming in, with an nested array/object structure. I use mapping to initially fill the model with my data. To update this, I want to extend the model if new data arrives, or update the existing data.
As far as I found out, the mapping option key, should do this trick for me, but I might have misunderstood the functionality of the mapping options.
I've boiled down the problem to be represented by this example:
var userMapping = {
key: function(item) {
return ko.utils.unwrapObservable(item.id);
}
};
// JSON call replaced with values
var viewModel = {
users: ko.mapping.fromJS([], userMapping)
};
// Should insert new - new ID?
ko.mapping.fromJS([{"id":1,"name":"Foo"}, {"id":2,"name":"Bar"}], userMapping, viewModel.users);
// Should only update ID#1 - same ID?
ko.mapping.fromJS([{"id":1,"name":"Bat"}], userMapping, viewModel.users);
// Should insert new - New ID?
ko.mapping.fromJS([{"id":3,"name":"New"}, {"id":4,"name":"New"}], userMapping, viewModel.users);
ko.applyBindings(viewModel);​
Fiddle: http://jsfiddle.net/mikaelbr/gDjA7/
As you can see, the first line inserts the data. All good. But when I try to update, it replaces the content. The same for the third mapping; it replaces the content, instead of extening it.
Am I using it wrong? Should I try to extend the content "manually" before using mapping?
Edit Solution:
I solved this case by having a second helper array storing all current models. On new data i extended this array, and updated the view model to contain the accumulated items.
On update (In my case a WebSocket message), I looped through the models, changed the contents of the item in question, and used method valueHasMutated() to give notice of changed value to the Knockout lib.
From looking at your example code the mapping plugin is behaving exactly as I would expect it to. When you call fromJS on a collection you are effectively telling the mapping plugin this is the new contents of that collection. For example:
On the second line, How could it know whether you were updating or whether you had simply removed id:2?
I can't find any mention of a suitable method that treats the data as simply an update, although you could add one. Mapped arrays come with some helpful methods such as mappedIndexOf to help you find particular items. If you receive an update data set simply loop through it, find the item and update it with a mapping.fromJS call to that particular item. This can easily be generalized into reusable method.
You can use ko.mapping.updateFromJS() to update existing values. However, it does not add new values so that would be a problem in your instance. Take a look at the link below for more details.
Using updateFromJS is replacing values when it should be adding them
Yes, you should first collect all data into a list or array and then apply the mapping to that list. Otherwise you are going to overwrite the values in your viewModel.

jQuery UI - autocomplete from a database

What are the steps for having jQuery UI's autocomplete use a database?
Specifically, how do I pass this script the entered value? How does autocomplete receive the script's json?
What I know:
1) Change the 'source option' to a script that queries the database.
2) ?
Current code:
$("#searchInput input").autocomplete({
source: "script_that_queries_the_db.php"
});
step 2? Have your php page mysql_query based on $_GET['term'] and return the results using json_encode.
Edit: Also, make sure the array you pass to json_encode is a flat array, otherwise jQueryUI won't read it as well as we'd like without writing more custom code.
The simplest way is to have your server return the results in json. See this example:
http://jqueryui.com/demos/autocomplete/#remote
Another way to do it is to make the request and parse the response yourself, by passing a function as source. See this example:
http://jqueryui.com/demos/autocomplete/#remote-with-cache
In either case the data passed to autocomplete must be an array of objects each with a label and a value.

jQuery AutoComplete Fill Array

I'm attempting to use jQuery's autocomplete feature, and after reading several posts I still have two questions:
1) I've gotten autocomplete to work with the code posted at the bottom, however I need the array titled "data" to be filled from our database. I've been trying to use different methods to fill this via AJAX. I tried using $.get and $.ajax. What is the correct syntax to accomplish this?
2) This array will be big, I will have 60,000 plus values if I just fill the array once. I was wondering if it's possible to perform an AJAX request to fill the array every-time the user enters a new letter? Is this better to do, or just fill the array with all values at once? By better, which taxes the system less?
//This code works
<script type="text/javascript">
$(document).ready(function(){
var data = "Facebook Gowalla Foursquare".split(" ");
$("#search_company").autocomplete(data);
});
</script>
//display company live search
echo('<form id="form" method="post" action="competitor_unlink.php" onsubmit="return">');
echo('Company: <input id="search_company"/>');
echo('<br/>');
echo('<button type="submit" value="Submit">Submit</button>');
echo('</form>');
Look at this demo - it's what you want to do (get data using ajax):
http://jqueryui.com/demos/autocomplete/#remote
You can pull data in from a local
and/or a remote source: Local is good
for small data sets (like an address
book with 50 entries), remote is
necessary for big data sets, like a
database with hundreds or millions of
entries to select from.
Autocomplete can be customized to work
with various data sources, by just
specifying the source option. A data
source can be:
an Array with local data a String,
specifying a URL a Callback The local
data can be a simple Array of Strings,
or it contains Objects for each item
in the array, with either a label or
value property or both. The label
property is displayed in the
suggestion menu. The value will be
inserted into the input element after
the user selected something from the
menu. If just one property is
specified, it will be used for both,
eg. if you provide only
value-properties, the value will also
be used as the label.
When a String is used, the
Autocomplete plugin expects that
string to point to a URL resource that
will return JSON data. It can be on
the same host or on a different one
(must provide JSONP). The request
parameter "term" gets added to that
URL. The data itself can be in the
same format as the local data
described above.
The third variation, the callback,
provides the most flexibility, and can
be used to connect any data source to
Autocomplete. The callback gets two
arguments:
1) A request object, with a single
property called "term", which refers
to the value currently in the text
input. For example, when the user
entered "new yo" in a city field, the
Autocomplete term will equal "new yo".
2) A response callback, which expects
a single argument to contain the data
to suggest to the user. This data
should be filtered based on the
provided term, and can be in any of
the formats described above for simple
local data (String-Array or
Object-Array with label/value/both
properties). It's important when
providing a custom source callback to
handle errors during the request. You
must always call the response callback
even if you encounter an error. This
ensures that the widget always has the
correct state.
Here's an example of how to specify a URL that will return the results from the database as JSON using the jQuery UI autocomplete plugin.
$("#search_company").autocomplete({
source: "/Search", // <-- URL of the page you want to do the processing server-side
minLength: 4 // <-- don't try to run the search until the user enters at least 4 chars
});
Autocomplete will automatically append a querystring parameter named "term" to the URL so your search page will need to expect that. Not sure what server technology you're using but since I'm a .NET developer here's an example in ASP.NET MVC :)
public ActionResult Search(string term) {
var results = db.Search(term); // <-- this is where you query your DB
var jqItems = new List<jQueryUIAutoCompleteItem>();
foreach (var item in results) {
jqItems.Add(new jQueryUIAutoCompleteItem() {
value = item.CompanyId.ToString(),
id = item.CompanyId.ToString(),
label = item.CompanyName
});
}
return Json(jqItems.ToArray(), JsonRequestBehavior.AllowGet);
}
jQueryUIAutoCompleteItem is just a data container that represents the JSON format that the autocomplete plugin expects.
public class jQueryUIAutoCompleteItem {
public string value { get; set; }
public string label { get; set; }
public string id { get; set; }
}
You're correct that sending the whole 60,000-record list to the client's machine doesn't sound like the best solution. You'll notice that Google only shows you a handful of the most popular matches in its autocomplete, as to many other websites.
You could shorten the list by waiting for the user to type two or three letters instead of searching on the first one.
You could do page chunking in the list (it goes by various names). That is, only return the top 10 or 15 matches. The user can get more of the list by scrolling or by clicking on a "Show More Results" link. You have to write (or search for) all the javascript code for this, of course.
It might be a bit late to this post but for others that find it. I created a plugin for jquery and the jqueryui autocomplete control that works with Foursquare. You can read the post and download the plugin at Foursquare Autocomplete Plugin

Categories