How to add List behavior to ReferenceManyField? - admin-on-rest

I have a list of 6k entries related to a ressource.
I would like to be able to list, search and paginate over them in a TabbedForm/FormTab. ReferenceManyField shows a limited number of entries.
What is the recommended way to extend ReferenceManyField or use List instead?

You can use the DataGrid component to large number of entries. I think there might be confusion on your part about List. List only fetches records and the actual rendering is done by DataGrid.
ReferenceManyField accepts filter, sort etc. parameters which you can use to control the number of records being fetched from your API.

According to those two issues: https://github.com/marmelab/admin-on-rest/issues/998 and https://github.com/marmelab/admin-on-rest/issues/561 you cannot use List in ReferenceManyField and the suggested way to do it is having a button that redirects you to the related List component with the proper filter.
Example:
class LinkToRelatedReviews extends React.Component {
render() {
return (<FlatButton
primary
label={ translate("Full list of reviews by user") }
icon={<ReviewsIcon />}
containerElement={
<Link to={{
pathname: '/reviews',
search: stringify({ filter: JSON.stringify({ userId: [this.props.params.id] }), page: 1 }),
}}
/>}
/>)
}
}
export default LinkToRelatedReviews;
Something like that can be put in UsersShow Component
<LinkToRelatedReviews params={props.match.params}/>
under DataGrid that doesn't provide pagination but can fetch some of the results for you.
You can also see it in action by navigating to: https://marmelab.com/admin-on-rest-demo/#/segments and clicking Customers. This will redirect you to CustomersList filtered by the specific segment.

Related

How to retrieve filtered items in Vuetify Datatable

Hi,
I have a vuetify datatable (backend Laravel) which has a filter on a column. I need to fetch the filtered data in the datatable and pass it to backend to generate a pdf.
I tried using current-items event on vuetify datatable but the result was incorrect. It only returns filtered data on first page.
Here is my "https://codepen.io/prasadchinwal5/pen/eYmbvYb". Please enter value 500 in the Less than filter under calories column and check the console.
Any help is appreciated.
You would take your underlying dataset and compute the array based on the same filter(s) used within the v-data-table column definition.
ie.
computed:{
currentItems(){
return this.desserts.filter(val=>val.calories < parseInt(this.calories))
},
currentItemsWithSearch(){
return this.currentItems.filter(val=> 'search logic here')
}
}
The currentItems value should then match the table's data.
This is applying a second & separate filter, similar to what you have done on the column definitions.
{
text: 'Calories',
value: 'calories',
filter: value => {
if (!this.calories) return true
return value < parseInt(this.calories)
},
}
Ideally, you would want to use the currentItems array as your data table items input, to account for the 'search' field you could chain further filters (search) on the computed output. This would perform less-than calorie filtering in a single place.
<v-data-table :items="currentItems" />

TYPO3 search box does not work after page is cached

There is a Problem with the Caching in TYPO3.
I have a simple search box that calls the itemRepository to get some items based on the search term. If no term is given, all Items are listed.
This works only for the first time.
After I hit the search button, the search term is cached and will always be used even if I enter a new search term.
The first term is always shown in the searchbox and used for the search. I have to clear the cache to make it work again.
Even when i put var_dump($terms); somwhere it generates an output for one time.
I know I could disable the cache for listAction, but this would make the page very slow since there are many items listed by default.
Is there a solution for this? Using TYPO3 8.7.8.
<!-- Searchbox -->
<f:form name="list" action="list" enctype="multipart/form-data">
<f:form.textfield name="terms" value="{terms}" placeholder="{f:translate(key:'enter_searchterm')}"/>
<button><f:translate key="search"/></button>
</f:form>
<!-- list with found items -->
<f:for each="{items}" as="item">
...
...
<li>{item.title}</li>
...
...
</f:for>
/**
* #param string $terms
*/
public function listAction($terms = "") {
$items = $this->itemRepository->findBySearch($terms);
$this->view->assign('items', $items);
$this->view->assign('terms', $terms);
}
You need to add list action in non-cacheable list in ext_localconf.php file.
// non-cacheable actions
[
'Controller' => 'list',
]
You should indeed set the list()-action with a search term parameter to non-cacheable.
To keep the performance for the non-filtered list you can add another non-cached action (without any parameters).
This way you can keep the performance on the non-filtered list.

How to use ng-repeat with an ajax request with DataTables?

Let's say I'd like to load a dataTable dynamically, but instead of using normal ajax function within datatable, I'd like to load it through Angular, use ng-repeat to generate the tr elements and then apply DataTables. Would that be possible? In broad terms, how could I do that?
I've got the ajax/ng-repeat working already like this:
angular.module('myApp', ['ngResource', 'ui.bootstrap'])
.factory('ProjectsService', ['$resource', function($resource) {
return $resource('/customers');
}])
.controller('AdminCustomersCtrl', ['ProjectsService', '$scope', function(ProjectsService, $scope) {
$scope.projects = ProjectsService.query();
}]);
The reason I'd like to do this is that all elements (data in the table) would be binded, so whenever the user edit an entry in the table, the change would be acknowledged immediately (visually) and also saved to the REST server. Each entry in the table would correspond to a mongo db document. So if anyone has any ideas of how to achieve this differently, I'd love suggestions.

Form select box in Backbone Marionette

I'm trying using Backbone.Marionette to build an application. The application gets its data through REST calls.
In this application I created a model which contains the following fields:
id
name
language
type
I also created an ItemView that contains a complete form for the model. The template I'm using is this:
<form>
<input id="model-id" class="uneditable-input" name="id" type="text" value="{{id}}"/>
<input id="model-name" class="uneditable-input" name="name" type="text" value="{{name}}" />
<select id="model-language" name="language"></select>
<select id="model-type" name="type"></select>
<button class="btn btn-submit">Save</button>
</form>
(I'm using Twig.js for rendering the templates)
I am able to succesfully fetch a model's data and display the view.
What I want to do now is populate the select boxes for model-language and model-type with options. Language and type fields are to be restricted to values as a result from REST calls as well, i.e. I have a list of languages and a list of types provided to me through REST.
I'm contemplating on having two collections, one for language and one for type, create a view for each (i.e. viewLanguageSelectOptions and viewTypeSelectOptions), which renders the options in the form of the template I specified above. What I am not sure of is if this is possible, or where to do the populating of options and how to set the selected option based on data from the model. It's not clear to me, even by looking at examples and docs available, which Marionette view type this may best be realized with. Maybe I'm looking in the wrong direction.
In other words, I'm stuck right now and I'm wondering of any of you fellow Backbone Marionette users have suggestions or solutions. Hope you can help!
Create a view for a Select in my opinion is not needed in the scenario that you are describing, as Im assuming that your languages list will not be changing often, and the only porpouse is to provide a list from where to pick a value so you can populate your selects in the onRender or initializace function of your view using jquery.
you can make the calls to your REST service and get the lists before rendering your view and pass this list to the view as options and populate your selects on the onRender function
var MyItemView = Backbone.Marionette.ItemView.extend({
initialize : function (options) {
this.languages = options.languages;
this.typeList = options.typeList;
},
template : "#atemplate",
onRender : function () {
this.renderSelect(this.languages, "#languagesSelect", "valueofThelist");
this.renderSelect(this.typeList, "#typesSelect", "valueofThelist")
},
renderSelect :function (list, element, value) {
$.each(list, function(){
_this.$el.find(element).append("<option value='"+this[value]+"'>"+this[value]+"</option>");
});
}
})
var languagesList = getLanguages();
var typeList = getTypesList();
var myItemView = new MyItemView({languages:languagesList,typeList :typeList });
Hope this helps.

Symfony 2.0 updating select options with JS?

I've been googling for hours but surprisingly I didn't find any topic on that subject.
I have the following Form
class propertyType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('city')
->add('district', 'entity', array('class'=>'FlatShanghaidefaultBundle:district',
'property'=>'name',
'query_builder' => function ($repository) {
$qb = $repository->createQueryBuilder('district');
$qb->add('where', 'city = :city');
$qb->setParameter('city', 1);
return $qb;
}
public function getName()
{
return 'property';
}
}
When the user choose a City in the form, I want the options of district to be dynamically updated and limited to that city. With Ajax or JS?
What would be the best practice? Do you know a tutorial on that topic?
If someone can put me on the right tracks, that would help a lot..
Thanks!
The query builder will not solve your problem, you can remove it altogether.
That query is run when the form gets built, once you have it on your browser you need to use javascript to populate the options.
You can have the options stored in a javascript variable, or pull them from the server as needed with ajax (you will need a controller to handle these ajax requests).
You will probably want to use some jquery plugin to handle the cascading logic between the select elements, there are a couple available:
I use this one, but it seems to be offline: http://devlicio.us/blogs/mike_nichols/archive/2008/05/25/jquery-cascade-cascading-values-from-forms.aspx
And there is this one, which I never used really: http://code.google.com/p/jquery-cascade/
There is also at least this Bundle I know of: https://github.com/genemu/GenemuFormBundle, which has ajax field types available for several jquery plugins. This may save you writing the ajax part to handle the data, as it comes built in (it's probably easier to implement the controller your self anyway). I haven't tried this one, and I don't know if it has cascading support.
Jbm is right about the query builder. And his approach is perfecly valid.
Another option could be to dispense the cascade select in favor of an autocomplete field.
Assuming that you save the countries, cities and districts as entities and have a relation between them, you do not even need to save what city/country has been selected because you can just call:
$district->getCity()->getCountry();
I have implemented a similar thing for country/city selection and will link here to the the main involved files.
First, create a custom form type to encapsulate all form stuff, it contains a hidden field to store the selected id and a text field to serve as input for the autocomplete logic:
https://github.com/roomthirteen/Room13GeoBundle/blob/master/Form/LocationFieldType.php
Then theme the form type:
https://github.com/roomthirteen/Room13GeoBundle/blob/master/Resources/views/Form/fields.html.twig
The url of the autocomplete source is passed as data attribute so no JS will be smutching the html code.
Last but not least, the JS functions have to be implemented:
https://github.com/roomthirteen/Room13GeoBundle/blob/master/Resources/public/jquery.ui.location-autocomplete.js
The result can be seen in the image below, see that for clarity the country name will be displayed in braces behind the city name:
--
I favor this solution much more that using cascade selects because the actual value can be selected in one step.
cheers
I'm doing this myself on a form.
I change a field (a product) and the units in which the quantity can be measured are updated.
I am using a macro with parameters to adapt it more easily.
The macro :
{% macro javascript_filter_unit(event, selector) %}
<script>
$(function(){
$('#usersection')
.on('{{ event }}', '{{ selector }}', function(e){
e.preventDefault();
if (!$(this).val()) return;
$.ajax({
$parent: $(this).closest('.child_collection'),
url: $(this).attr('data-url'),
type: "get",
dataType: "json",
data: {'id' : $(this).val(), 'repo': $(this).attr('data-repo'), parameter: $(this).attr('data-parameter')},
success: function (result) {
if (result['success'])
{
var units = result['units'];
this.$parent.find('.unit').eq(0).html(units);
}
}
});
})
});
</script>
{% endmacro %}
The ajax returns an array : array('success' => $value, 'units' => $html). You use the $html code and put it in place of the select you want to change.
Of course the javascript code of the ajax call need to be modfied to match your fields.
You call the macro like you would normally do:
{% import ':Model/Macros:_macros.html.twig' as macros %}
{{ macros.javascript_filter_unit('change', '.unitTrigger') }}
So I have two arguments : the event, often a change of a select. and a selector, the one whose change triggers the ajax call.
I hope that helps.

Resources