jquery ui autocomplete database - database

I'd like to use jQuery UI autocomplete in order to load a list from my database but I don't know wich method I should use to do so.
I tried to use the "Remote datasource" method http://jqueryui.com/demos/autocomplete/#remote, but it obviously doesn't work.
I have the following code :
js:
$(function() {
$("#client").autocomplete({
source: "nom.php",
minLength: 2,
select: function(event, ui) {
alert(ui);
}
});
});
html :
<label for="client">Client</label>
<input name="client" id="client" class="ui-autocomplete ui-widget-content ui-corner-all" />
php:
$query = "SELECT nom from personne";
$result = mysql_query($query, $db);
while($row = mysql_fetch_assoc($result)) {
foreach($row as $val)
$tab[] = $val;
}
print json_encode($tab);
It does show all the values no matter what I enter, but when I copy the result of nom.php and past it next to source: it does work...
thank you for your helm

The problem is that you are not filtering the results server side.
When you use a local collection, the local collection gets automatically filtered by autocomplete.
However, when using a remote source, the source is supposed to filter. I guess this is to save bandwidth so that the server only send the matching items, and not all items and let the browser filter at it's end.
When calling your server side method, autocomplete also sends a parameter called term that you can use to filter.
You can get hold of the entered value like this in your php script:
$term = trim(strip_tags($_GET['term']));
Then in your foreach, only add the items matching the filter to your collection before you send it back again.

Related

Angular Select not updating if model changes

I am working on a website which uses Angular (1.6.4) Select. The content for the select element is loaded via REST if it is requested the first time. But the response of the REST call is cached so that following calls load the data from memory. If I load the website the select element is empty and I can't select any value. If I visit the site again with the data cached, the selectbox allows you to select items from a list. If I redirect the REST call to a file containing the data it works on the first attempt and I can select items as expected
So it seems that the code works in principle but if the model is updated too late the select element does not notice the changes.
Here is the code I am using:
<select ng-model="myData" chosen
class="select--chosen"
ng-change="handleSelection()"
ng-options="myData as myData.value for myData in dataArray">
</select>
The controller code looks like this (called when site is opened):
$scope.dataArray = [];
//$scope.dataArray = [{value : "just a test value"}];
$scope.$watch('dataArray ', function() {console.log("dataArray was changed...")}, true);
getArray();
function getArray() {
DataFactory.getArray().then(function (data) {
$scope.dataArray = data;
});
}
I do get the watch message when I load the site for the first time. When looking for a solution I found several hints but none of them worked for me. This is what I tried:
1) Add
$scope.$apply(function(){ /* code */ });
to set the dataArray inside this function or call it inside of the watch-function. In both cases I got the error on the console that the digest is already updating or so, indicating that it is not neccessary to use scope.$apply
2) Use
$scope.onChange($scope.dataArray);
after setting dataArray = data.
Unfortunately nothing worked. If I uncomment the line:
$scope.dataArray = [{value : "just a test value"}];
I can choose this entry after loading the page and the select view then shows the first entry of the dataArray and afterwards I can access the whole list and select items from it.
So I would like to know what I can do to update the select view after the data is available. Either by adding a Listener or by manually calling the select view to update(), refesh() or so. Is there such a function available?
You can show your select element by some boolean flag, which sets true, when
data loaded.
You can do something like below code.
In controller :
$scope.dataArray = [];
$scope.myData= null;
$scope.isDataLoaded = false; //flag for data loading.
function getArray() {
DataFactory.getArray().then(function (data) {
$scope.isDataLoaded = true; // make true now
$scope.dataArray = data.data; //your result might be data.data
$scope.myData = $scope.dataArray[0]; // you may select 1st as default
});
}
getArray();
In html:
<select ng-if="isDataLoaded" ng-model="myData" ng-class="select-chosen"
ng-options="myData as myData.value for myData in dataArray">
</select>

Pagination on ruby array without sending request to controller

I have a array of arrays in my rails application and it is something like:
#array=[[1, "Mr.X", "developer"], [2, "Mr.Y", "python"]...... [n, "Mr.Z", "ba"]]
I am getting these records on runtime from a different database server by using SQL query not from ActiveRecord. I want to perform pagination on this data and I am using will_paginate/array
#array = #array.paginate(:page => 1, :per_page => 1)
and in my view, I am calling it by:
<%= will_paginate #array%>
It is showing me the data of one record for the first page and links for other pages, however when clicked on next page link, it is giving the error for nil:nil class, as it is again submitting the parameters but this time, the parameters are not appropriate.
I have the final records in #array and I don't want to send the request in backend again and again and I just want to process it on front end only.
Thanks in advance.
Note: I am having different issue, while submitting the form on the post method for first time, my params are
params = <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"EEzvZTAdFAGZ1vOvfeQ/hx7BmDFknC+xHpP4HdhIUncfZDobL1le1vzeanLRdgVFQtKYLGPCgKOfqf5J9+4J2Q==", "check_box_array"=>["ID", "NAME", "ROLE"], "column_value"=>{"ID"=>"", "NAME"=>"", "ROLE"=>""}, "table_name"=>"employee", "column_length"=>"3", "commit"=>"Search", "controller"=>"test", "action"=>"index"}
and here on the controller index action I am running SQL query and fetching data from database not using any model and storing the results into array, which I am passing to view like ` <%= will_paginate #array %>
But while clicking on any page number, it is submitting the parameters as <ActionController::Parameters {"page"=>"2", "controller"=>"test", "action"=>"index"} permitted: false>
and this time, it is not having any query parameters and it is generating the error for nil class
undefined method for nil:NilClass
But I don't want to send the query parameters, I just want to show the data of #array using pagination i.e. on every page just the required data.

Angular. Watch for selected values inside ng-repeat list and pass them to service

I'm new to AngularJS and tried to find solution with no success.
I have dynamic form with nested ng-repeats as custom directives. Here is my structure in plunker.
In directive "rule" i have two selects, one for parameters another one for values.
<rule ng-repeat="rule in cc.route.rules track by rule.id">
<li class="second-level">
{{ $index +1 }}
<select ng-change="ic.getParamName(mc.main.routes[$parent.$index].rules[rule.id].param)"
ng-model="mc.main.routes[$parent.$index].rules[rule.id].param"
ng-options="param.name as param.name for param in ic.params"></select>
<select ng-change="" ng-model="mc.main.routes[$parent.$index].rules[rule.id].value"
ng-options="value.code as value.name for value in ic.values"></select>
<button ng-click="ic.removeRule(rule,$parent.$index)">del</button>
</li>
</rule>
When i select the parameter it fires the function with passing the parameter's name.
In the controller of current directive i catch this parameter by switch case and pass it to the certain method in service. Then i get the list of values for this parameter.
case "Countries":
vm.values = DataService.getCountries();
break;
case "Cities":
DataService.getCities().then(function(data){
vm.values = data;
});
break;
My issue is that I want to get cities only if some country is already selected in previous ng-repeats(rules) of current route (we can catch only the last selected country if there are more than one), and when i'm adding the new rule with cities, pass the code of the country selected above as argument to the certain method in service to make http request and get cities for this country. Same issue with OS and OS versions.
How i can watch for rules in current route and path the codes of countries and OS to the service with adding new rule?
UPDATE:
Let's say we add new route and want there 2 rules with country "USA" and city "Dallas". We need to add new rule to this route, choose the parameter "Countries" in the first select and the value "USA" in the second. Then we want to choose "Dallas", but my server can return american cities only if i pass the country code "US" to http request. So at the moment when we add new rule and choose the parameter "Cities" we need to get all values from all selects above, check if there was country and get it country code, then path it to the service with getCities() method.
Thanks! And please let me know if it is not well understood.
Re-factor the User Interface
Currently as designed the UI has an Add new Rule button that allows the user to add illegal rules. As shown in the screenshot, the user has erroneously added two countries. And as stated by the OP, users can add a Cities rule before a country is selected.
The advice is to change the Add new Rule button to a drop-down menu that has illegal options disabled. When rules are added or removed, the controller should enable or disable appropriate legal items.
The ng-options directive allows a controller to enable and disable options using the disable when clause. For more information, visit AngularJS ng-options API Reference.
The UI should not allow the user to add illegal rules. Also the Submit button should be disabled until the form is complete. Users should be given advice on how to complete the form. "Add Route", "Select Rule", "Select Country", etc.
XHR Request Issues
In the PLNKR the DataService.getCities function has several problems.
//WRONG
function DataService() {
return {
getCities: function (code) {
$http.get('/get_cities?country_code=' + code)
.success(function (response) {
return(response.data);
});
The return statement doesn't return a value to the getCities function. It returns values to the anonymous function inside the .success method and the .success method ignores return values.
//BETTER
function DataService($http, $q) {
return {
getCities: function (code) {
if (isBad(code)) {
return $q.reject("BAD Country Code");
};
//Otherwise send request
var getCitiesPromise = (
$http.get('/get_cities?country_code=' + code)
.then(function onFulfilled (response) {
return(response.data);
});
);
return getCitiesPromise;
}
}
};
In this example, the getCities function checks the country code and returns a rejected promise if the code is bad. If the country code is OK, an XHR request is sent and a promise is return fulfilled with the data or rejected with the $http service error.

How to update view in angular, when database has changed?

Ive got a SPA using angular and 2 databases in firebase.
So theres a control (with 2 options) where i'd like choose database to get data. For example first option means 1st database, second option means 2nd one.
The question is: "how to update view in angular, when database has changed".
<select class="form-control" ng-model="level" ng-options="lvl in lvls"></select>
<div>{{data}}</div>
in controller
var levelString = "https://amber-inferno-9289.firebaseio.com/" + $scope.level + "/";
$scope.dictionary = new Firebase(levelString);
$scope.dictionary.on('value', function(snapshot){
$scope.data = snapshot.val();
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
I think what you're looking to do is use the ng-change directive on your select and refactor your dictionary set up logic into a function that is called on select change.
<select class="form-control" ng-model="level" ng-options="lvl for lvl in lvls" ng-change="setUpDictionary(level)"></select>
Then in your controller, create the setUpDictionary function to set $scope.dictionary to a new Firebase pointing at a different url etc.
I think this is what you're looking for based on what I could make from your question.
Hope it helps you out!

Setting default <select> value with asynchronous data

I have a drop-down list
<select ng-model="referral.organization"
ng-options="key as value for (key, value) in organizations">
</select>
where organizations is filled using a $http request. I also have a resource referral which includes several properties, including an integer organization that corresponds to the value saved in the drop-down. Currently, the drop-down works fine and selecting a new value will update my referral resource without issue.
However, when the page loads the drop-down is blank rather than displaying the value of referral.organization that was retrieved from the server (that is, when opening a previously saved referral form). I understand that this is likely due to my resource being empty when the page first loads, but how do I update the drop-down when the information has been successfully retrieved?
Edit:
{{ organizations[referral.organization] }} successfully lists the selected value if placed somewhere else on the page, but I do not know how to give the tag this expression to display.
Second Edit:
The problem was apparently a mismatch between the key used in ngOptions and the variable used in ngModel. The <select> option's were being returned as strings from WebAPI (despite beginning as Dictionary) while the referral model was returning integers. When referral.organization was placed in ngModel, Angular was not matching 2723 to "2723" and so forth.
I tried several different things, but the following works well and is the "cleanest" to me. In the callback for the $resource GET, I simply change the necessary variables to strings like so:
$scope.referral = $resource("some/resource").get(function (data) {
data.organization = String(data.organization);
...
});
Not sure if this would be considered a problem with Angular (not matching 1000 to "1000") or WebAPI (serializing Dictionary<int,String> to { "key":"value" }) but this is functional and the <select> tag is still bound to the referral resource.
For simple types you can just set $scope.referral.organization and it'll magically work:
http://jsfiddle.net/qBJK9/
<div ng-app ng-controller="MyCtrl">
<select ng-model="referral.organization" ng-options="c for c in organizations">
</select>
</div>
-
function MyCtrl($scope) {
$scope.organizations = ['a', 'b', 'c', 'd', 'e'];
$scope.referral = {
organization: 'c'
};
}
If you're using objects, it gets trickier since Angular doesn't seem smart enough to know the new object is virtually the same. Unless there's some Angular hack, the only way I see forward is to update $scope.referral.organization after it gets loaded from the server and assign it to a value from $scope.organizations like:
http://jsfiddle.net/qBJK9/2/
<div ng-app ng-controller="MyCtrl">
<select ng-model="referral.organization" ng-options="c.name for c in organizations"></select>
{{referral}}
<button ng-click="loadReferral()">load referral</button>
</div>
-
function MyCtrl($scope) {
$scope.organizations = [{name:'a'}, {name:'b'}, {name:'c'}, {name:'d'}, {name:'e'}];
$scope.referral = {
organization: $scope.organizations[2]
};
$scope.loadReferral = function () {
$scope.referral = {
other: 'parts',
of: 'referral',
organization: {name:'b'}
};
// look up the correct value
angular.forEach($scope.organizations, function(value, key) {
if ($scope.organizations[key].name === value.name) {
$scope.referral.organization = $scope.organizations[key];
return false;
}
});
};
}
You can assign referral.organization to one of objects obtained from ajax:
$scope.referral.organization = $scope.organizations[0]
I created simple demo in plunker. Button click handler changes list of objects and selects default one.
$scope.changeModel = function() {
$scope.listOfObjects = [{id: 4, name: "miss1"},
{id: 5, name: "miss2"},
{id: 6, name: "miss3"}];
$scope.selectedItem = $scope.listOfObjects[1];
};
The other answers were correct in that it usually "just works." The issue was ultimately a mismatch between the organization key (an integer) stored inside $scope.organizations and the key as stored in the $http response, which is stored in JSON and therefore as a string. Angular was not matching the string to the integer. As I mentioned in my edit to the original question, the solution at the time was to cast the $http response data to a string. I am not sure if current versions of Angular.js still behave this way.

Resources