Hi I am trying to implement a autocomplete field using Zend Jquery. I followed a tutorial to grab the data from an array and I have extended the code to access the data from my mysql table.
IndexController.php
$this->view->autocompleteElement = new ZendX_JQuery_Form_Element_AutoComplete('ac');
$this->view->autocompleteElement->setLabel('Autocomplete');
$this->view->autocompleteElement->setJQueryParam('source', '/index/city');
This calls the cityAction()
public function cityAction()
{
$results = Application_Model_City::search($this->_getParam('term'));
$this->_helper->json(array_values($results));
}
I then call the Model City
public static function search($term)
{
$region = new Application_Model_DbTable_Regions();
$results = $region->getRegion($term);
return $results;
}
And finally the Regions db model
public function getRegion($term)
{
$select = $this->select()->from($this,'City')
->where('City LIKE ? ',$term.'%');
return $this->fetchAll($select)->toArray();
}
Now when I go the autocomplete field it shows the results but as UNDEFINED , I think its something to do the way I am send the data back to the json helper.
I used firebug and I can see the data is been pulled in the following format.
[{"City":"London"},{"City":"Londonderry"},{"City":"Longfield"},{"City":"Longhope"},{"City":"Longniddry"}]
I think this format is incorrect, please any body dealt with this before?
Cheers
J
The ZendX_JQuery_Form_Element_AutoComplete element is a proxy to the AutoComplete View Helper, which is a proxy to the jQuery UI Autocomplete widget.
If you read the overview on the jQuery UI Autocomplete page, you will note:
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.
So, the JSON you are returning to the autocomplete should be structured more like:
[{"label":"London","value":"London"},{"label":"Londonderry","value":"Londonderry"},{"label":"Longfield","value":"Longfield"}]
Good luck!
Fixed the problem afters hours of pain!
I modified the below code where it accesses the data
public function getRegion($term)
{
$select = $this->select()->from($this,'City')
->where('City LIKE ? ',$term.'%');
return $this->fetchAll($select)->toArray();
}
I added a line of SQL City AS Value
public function getRegion($term)
{
$select = $this->select()->from($this,'City AS value')
->where('City LIKE ? ',$term.'%');
return $this->fetchAll($select)->toArray();
}
This seems to have worked!
Cheers
J
Related
I have a pretty standard Xamarin form that uses template pages for some overview data. When the user taps an entry I take them to a details page. The data comes from a server via an API. The details is held in a class behind the overview form/template. When the user taps the form I Jsonconvert.SerializeOvbject and pass it to the details page for processing. This process works fine under normal conditions. However when the data has a hash tag # (aka pound, aka sharp) in the data the the json is truncated at the point where it appeared in the string.
The meat of the tapped event in the template:
var forminfo = JsonConvert.SerializeObject(ea.Parameter);
Routing.RegisterRoute(nameof(TrackWarrantPageX), typeof(TrackWarrantPageX));
await Shell.Current.GoToAsync($"{nameof(TrackWarrantPageX)}?{nameof(TrackWarrantPageX.Contentx)}={forminfo}");
However in the details page the string that is received is truncated at the # sign.
Here is how the string arrives at the details page (only relevant code is shown).
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(Contentx), nameof(Contentx))]
public partial class TrackWarrantPageX : ContentPage
{
string contentx = "";
public string Contentx
{
get => contentx;
set
{
contentx = Uri.UnescapeDataString(value ?? string.Empty);
OnPropertyChanged();
PopulateForm(contentx); *<<<===== this is the first place I can inspect the contents and it is truncated*
}
}
I played around with this line
contentx = Uri.UnescapeDataString(value ?? string.Empty);
and did some research but came up short. So any help would be greatly appreciated.
Based on #Jason suggestion I researched URLencoding and stumbled upon Uri.EscapDataString (encode). Since the page performed a Uri.UnescapeDataString (decode) it would best to encode it first. So I added one line of code on the tap event of the template and it looks like this:
var forminfo = JsonConvert.SerializeObject(ea.Parameter);
string _forminfo = Uri.EscapeDataString(forminfo); <<<===NEW LINE OF CODE
await Shell.Current.GoToAsync($"{nameof(TrackWarrantPageX)}?{nameof(TrackWarrantPageX.Contentx)}={_forminfo }");
So now the string is preserved on the page side. Thanks Jason.
I'm working with a non-profit cat shelter trying to update their website. They want to have a page that connects to their shelter manager software to display the available cats for adoption. Luckily, their shelter manager offers API calls to get the information I need from it.
They use Wix as their platform and are pretty set on keeping it as most of their volunteers know how to make easy adjustments to other pages. I researched and found Wix offers the ability to connect to the API using their fetch method.
Basically, I am trying to get a dynamic page to display a repeater that is populated from their json API Get method.
Currently, for the backend I have (URL to API removed for security):
import {fetch} from 'wix-fetch';
export function getdata(){
return fetch('URL to API Service', {method: 'get'})
.then( (httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
}
} );
}
On the page, this is where I think I am getting stuck:
import {getdata} from 'backend/fetchCats';
getdata()
.then(json => {
console.log(json);
var catData = json;
// static repeater data
$w.onReady(function () {
// handle creation of new repeated items
$w("#repeater1").onItemReady( ($item, itemData, index) => {
$item("#text23").text = itemData.ANIMALNAME;
} );
// set the repeater data, triggering the creation of new items
$w("#repeater1").data = catData;
} );
});
The above is giving me the error: Wix code SDK error: Each item in the items array must have a member named _id which contains a unique value identifying the item.
I know the JSON call has an ID field in it, but I am guessing Wix is expecting an _id field.
Am I just doing this wrong? Or am I missing something simple? I've spent a couple nights searching but can't really find a full example online that uses Wix's fetch method to get data via my HTTPS Get.
Thanks for any help!
You are doing fine.
You are getting the error from the line $w("#repeater1").data = catData;
which is the line used to set the items into the repeater. A repeater expects to have a _id member for each of the items, and your data quite probably does not have such an attribute.
I assume the API you are using, when returning an array, each item has some identifying attribute? if so, you can just do a simple transform like -
let catDataWithId = catData.map(item => {
item._id = item.<whatever id attribute>;
return item;
});
$w("#repeater1").data = catData;
This is a slightly messy questions. Although it appears I'm asking question about amCharts, I really just trying to figure how to extract an array from HTTP request and then turn it into a variable and place it in to 3-party javacript.
It all starts here, with this question, which was kindly answered by AmCharts support.
As one can see from the plnker. The chart is working. Data for the chart is hard coded:
`var chartData = [{date: new Date(2015,2,31,0,0,0, 0),value:372.10,volume:2506100},{date: new Date(2015,3,1,0, 0, 0, 0),value:370.26,volume:2458100},{date: new Date(2015,3,2,0, 0, 0, 0),value:372.25,volume:1875300},{date: new Date(2015,3,6,0, 0, 0, 0),value:377.04,volume:3050700}];`
So we know the amCharts part works. Know where the problem is changing hard coded data to a json request so it can be dynamic. I don't think this should be tremendously difficult, but for the life of me I can't seem figure it out.
The first issue is I can't find any documentation on .map, .subscribe, or .observable.
So here is a plunker that looks very similar to the first one, however it has an http providers and injectable. It's broken, because I can't figure out how to pull the data from the service an place it into the AmCharts function. I know how pull data from a http provider and display it in template using NgFor, but I don't need it in the template (view). As you can see, I'm successful in transferring the data from the service, with the getTitle() function.
this.chart_data =_dataService.getEntries();
console.log('Does this work? '+this.chart_data);
this.title = _dataService.getTitle();
console.log('This works '+this.title);
// Transfer the http request to chartData to it can go into Amcharts
// I think this should be string?
var chartData = this.chart_data;
So the ultimate question is why can't I use a service to get data, turn that data into a variable and place it into a chart. I suspect a few clues might be in options.json as the json might not be formatted correctly? Am I declaring the correct variables? Finally, it might have something to do with observable / map?
You have a few things here. First this is a class, keep it that way. By that I mean to move the functions you have inside your constructor out of it and make them methods of your class.
Second, you have this piece of code
this.chart_data =_dataService.getEntries().subscribe((data) => {
this.chart_data = data;
});
What happens inside subscribe runs asynchronously therefore this.chart_data won't exist out of it. What you're doing here is assigning the object itself, in this case what subscribe returns, not the http response. So you can simply put your library initialization inside of the subscribe and that'll work.
_dataService.getEntries().subscribe((data) => {
if (AmCharts.isReady) {
this.createStockChart(data);
} else {
AmCharts.ready(() => this.createStockChart(data));
}
});
Now, finally you have an interesting thing. In your JSON you have your date properties contain a string with new Date inside, that's nothing but a string and your library requires (for what I tested) a Date object, so you need to parse it. The problem here is that you can't parse nor stringify by default a Date object. We need to convert that string to a Date object.
Look at this snippet code, I used eval (PLEASE DON'T DO IT YOURSELF, IS JUST FOR SHOWING PURPOSES!)
let chartData = [];
for(let i = 0; i < data[0].chart_data.length; i++) {
chartData.push({
// FOR SHOWING PURPOSES ONLY, DON'T TRY IT AT HOME
// This will parse the string to an actual Date object
date : eval(data[0].chart_data[i].date);
value : data[0].chart_data[i].value;
volume : data[0].chart_data[i].volume;
});
}
Here what I'm doing is reconstructing the array so the values are as required.
For the latter case you'll have to construct your json using (new Date('YOUR DATE')).toJSON() and you can parse it to a Date object using new Date(yourJSON) (referece Date.prototype.toJSON() - MDN). This is something you should resolve in your server side. Assuming you already solved that, your code should look as follows
// The date property in your json file should be stringified using new Date(...).toJSON()
date : new Date(data[0].chart_data[i].date);
Here's a plnkr with the evil eval. Remember, you have to send the date as a JSON from the server to your client and in your client you have to parse it to a Date.
I hope this helps you a little bit.
If the getEntries method of DataService returns an observable, you need to subscribe on it to get data:
_dataService.getEntries().subscribe(
(data) => {
this.chart_data = data;
});
Don't forget that data are received asynchronously from an HTTP call. The http.get method returns an observable (something "similar" to promise) will receive the data in the future. But when the getEntries method returns the data aren't there yet...
The getTitle is a synchronous method so you can call it the way you did.
Consider a REST URL like /api/users/findByCriteria which receives POSTed JSON that contains details of the criteria, and outputs a list of Users.
How would one call this with Restangular so that its results are similar to Restangulars getList()?
Restangular.all('users').post("findByCriteria", crit)... might work, but I don't know how to have Restangular recognize that the result will be a list of Users
Restangular.all('users').getListFromPOST("findByCriteria", crit)... would be nice to be able to do, but it doesn't exist.
Doing a GET instead of a POST isn't an option, because the criteria is complex.
Well,
I experience same problem and I workaround it with plain function, which return a plain array of objects. but it will remove all Restangular helper functions. So, you cant use it.
Code snippet:
Restangular.one('client').post('list',JSON.stringify({
offset: offset,
length: length
})).then(
function(data) {
$scope.clients = data.plain();
},
function(data) {
//error handling
}
);
You can get a POST to return a properly restangularized collection by setting a custom handler for OnElemRestangularized in a config block. This handler is called after the object has been Restangularized. isCollection is passed in to show if the obect was treated as a collection or single element. In the code below, if the object is an array, but was not treated as collection, it is restangularized again, as a collection. This adds all the restangular handlers to each element in the array.
let onElemR = (changedElem, isCollection, route, Restangular: restangular.IService) => {
if (Array.isArray(changedElem) && !isCollection ) {
return Restangular.restangularizeCollection(null, changedElem, changedElem.route);
}
return changedElem;
};
RestangularProvider.setOnElemRestangularized(onElemR);
Good evening everyone. I am currently using MVC 3 and I have a viewmodel that contains a property that is a List. I am currently using json2's JSON.stringify method to pass my viewmodel to my action method. While debugging I am noticing that all the simple properties are coming thru but the collection property is empty even though I know for sure that there is at least one object in the collection. I wanted to know if there is anyone that is running into the same issue. Below is the code that I am using to post to the action method:
$.post("/ReservationWizard/AddVehicleToReservation/",
JSON.stringify('#ViewData["modelAsJSON"]'),
function (data) {
if (data != null) {
$("#vehicle-selection-container").html(data);
$(".reservation-wizard-step").fadeIn();
}
});
The object #ViewData["modelAsJSON"] contains the following json and is passed to my action method
{"NumberOfVehicles":1,"VehiclesToService":[{"VehicleMakeId":0,"VehicleModelId":0}]}
As you can see the property "VehiclesToService" has one object but when it gets to my action method it is not translated to the corresponding object in the collection, but rather the collection is empty.
If anyone has any insight into this issue it would be greatly appreciated.
Thanks in advance.
UPDATE
OK after making the recommended changes and making the call to new JavaScriptSerializer().Serialize(#Model) this is the string that ultimately gets sent to my action method through the post
'{"NumberOfVehicles":1,"VehiclesToService":[{"VehicleMakeId":0,"VehicleModelId":0}]}'
I can debug and see the object that gets sent to my action method, but again the collection property is empty and I know that for sure there is at least one object in the collection.
The AddVehicleToReservation action method is declared as follows:
public ActionResult AddVehicleToReservation(VehicleSelection selections)
{
...
return PartialView("viewName", model);
}
Here's the problem:
JSON.stringify('#ViewData["modelAsJSON"]')
JSON.stringify is a client side function and you are passing as argument a list that's stored in the ViewData so I suppose that it ends up calling the .ToString() and you have
JSON.stringify('System.Collections.Generic.List<Foo>')
in your final HTML which obviously doesn't make much sense. Also don't forget that in order to pass parameters to the server using the $.post function the second parameter needs to be a javascript object which is not what JSON.stringify does (it generates a string). So you need to end up with HTML like this:
$.post(
'ReservationWizard/AddVehicleToReservation',
[ { id: 1, title: 'title 1' }, { id: 2, title: 'title 2' } ],
function (data) {
if (data != null) {
$('#vehicle-selection-container').html(data);
$('.reservation-wizard-step').fadeIn();
}
}
);
So to make this work you will first need to serialize this ViewData into JSON. You could use the JavaScriptSerializer class for this:
#{
var myList = new JavaScriptSerializer().Serialize(ViewData["modelAsJSON"]);
}
$.post(
'#Url.Action("AddVehicleToReservation", "ReservationWizard")',
// Don't use JSON.stringify: that makes JSON request and without
// proper content type header your sever won't be able to bind it
#myList,
function (data) {
if (data != null) {
$('#vehicle-selection-container').html(data);
$('.reservation-wizard-step').fadeIn();
}
}
);
And please don't use this ViewData. Make your views strongly typed and use view models.