I have a project where I'm using BreezeJS to fetch data from my webserver. I'm using AngularJS with the ui-select2 module. Currently, I have it where when I load my page, breezejs makes a call to fetch the data that I dump into a scope variable. From there, select2 can easily make the reference to it and build accordingly.
If I want to ajaxify things, it gets really tricky. I want to have the ability to use select2's ajax or query support, but instead of using it to fetch data, I want to use breezejs to do it. So during a page load, nothing is loaded up until I start typing in X minimum characters before it makes an ajax fetch.
Constraints: I do not want fetch data using select2's "ajax". I want BreezeJS to handle the service calls. When I use ajax, it makes an ajax call everytime I press a character in order to filter the results (and resemble autocomplete). I just want the list to load up once and use the native filtering after that.
Here is what I have so far:
breezejs - StateContext.JS
m.app.factory('StateContext', ['$http', function ($http) {
configureBreeze();
var dataService = new breeze.DataService({
serviceName: "/Map/api",
hasServerMetadata: false
});
var manager = new breeze.EntityManager({ dataService: dataService});
var datacontext = {
getAllStates: getAllStates
};
return datacontext;
function getAllStates() {
var query = breeze.EntityQuery
.from("States");
return manager.executeQuery(query);
}
function configureBreeze() {
breeze.config.initializeAdapterInstances({ dataService: "webApi" });
}
}]);
This works and returns my json object correctly.
Here is how I call the service:
m.app.controller('LocationCtrl', ['$scope', 'StateContext', function ($scope, StateContext) {
$scope.getAllStates = function () {
StateContext.getAllStates().then(stateQuerySucceeded).fail(queryFailed);
}
$scope.getAllStates();
$scope.states = [];
function stateQuerySucceeded(data) {
data.results.forEach(function (item) {
$scope.states.push(item);
});
$scope.$apply();
console.log("Fetched States");
}
function queryFailed(error) {
console.log("Query failed");
}
$scope.select2StateOptions = {
placeholder: "Choose a State",
allowClear: true,
minimumInputLength: 2
};
}
and here is my html:
<div ng-app="m" id="ng-app">
...
...
<select ui-select2="select2StateOptions" ng-model="LocationModel.State">
<option value=""></option>
<option ng-repeat="state in states" value="{{state.id}}">{{state.name}}</option>
</select>
</div>
Currently the html select2 control loads up when the page loads. But I want to have it so when I type in more than 2 characters, I'll be able to make the call to $scope.getAllStates(); as an ajax call. BreezeJS already uses ajax natively when configuring the BreezeAdapter for webapi.
I was thinking about using select2's ajax, or query calls.. but I'd rather use breeze to fetch the data, since it makes querying extendable, and I don't want to violate my design pattern, or make the code harder to maintain, and I don't want the ajax calls to be made everytime I enter a new character into the textbox, I just want it to occur once.
Close attempt:
changed my html to:
<!-- Select2 needs to make this type="hidden" to use query or ajax, then it applies the UI skin afterwards -->
<input type="hidden" ui-select2="select2StateOptions" ng-model="LocationModel.State" /><br />
in my controller, changing select2StateOptions:
$scope.select2StateOptions = {
placeholder: "Choose a State",
allowClear: true,
minimumInputLength: 2,
query: function (query) {
debugger;
var data = StateContext.getAllStates().then(stateQuerySucceeded).fail(queryFailed);
}
};
Here's the problem. BreezeJS uses a Q library, which makes use of a thing called a "promise"; which is a promise that data will be returned after making the ajax call. The problem with this, the query function is expecting data to be populated, but the promise to call the "stateQuerySucceeded" function is made after returning from the query function.
So it hits the query function first. Then hits getAllStates(). Returns from the query (nothing is populated), then "stateQuerySucceeded" is called after that.
In otherwords, even though I have been able to fetch data, this is done too late.. select2's query function did not receive the data at the right time, and my html select is hanging on "Searching ... " with a search spinner.gif.