Giter Site home page Giter Site logo

Comments (25)

dpgaspar avatar dpgaspar commented on May 3, 2024

The usecase you describe does not exist. You can only filter select fields individually.

Your right this could be an interesting feature....

To develop this you must develop the template yourself. Then override the edit_template property.

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

I might give it bash. A concrete example is some-one needs to add a new item to a store. They first select an item group say fruits, then select an actual item which then gives a drop down list of apple, banana etc. They then add quantity price etc and submit.

Currently one of the ways to do this is to overload the repr_ of an model to be '%s -%s' %(self.group,self.name) so that a user can manually add the filter in the select2 text box by typing the group, essentially duplicating inputs but still not having to scroll down a long list.

Once you have cascading filters based on inputs you can start doing really fancy stuff like forcing users to only select items that are part of a particular hierarchy all on one simple form.

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

Yes, this is a recurring problem/feature when developing a web app.

One way to do it: when the user selects a 'master' combo the form reloads (or submits to a specific endpoint) the server populates the slave combos and renders the form again.

Another way: when the user selects a 'master' combo fires something like jQuery.getJSON() to a specific endpoint the server returns Json data for the slave combo(s).

What would be the best way to define an API for this feature? regarding of course the current API for ModelView or extending Model from SqlAlchemy. Any ideas ?

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

Option A: Clean less flexible relies on metadata look ups to determine fk and many to many etc.

add_form_cascade_query=[('field_name',['parent1_field_name','parent2_field_name'])]

Option B: Flexible, similar to existing query API

add_form_query_cascade = [('field_name', 'parent field'
SQLAModel,
[['column of related object',FilterObject,'parent field's object's column name']]
)]

Here you should be able to specify multiple field names and a field name multiple times.

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

good suggestions, need some time to think about it

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

I just had a bit of a rethink about this API and the API for filters in general. I came up with the following: Each filter is simply function that accepts a query and then returns a query.

Eg: lambda query: query.join(Mod).filter(Mod.id==55)

Then the api for the cascading filter could just be a function that accepts the current state of the form and a query object and returns a query object.

Eg: lambda query,item: query.join(SomeMod).filter(SomMOd.name=item.som_mod.name)

This api could then technically apply to all filters and user just needs understand the principal of one API.

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

My last comment feels kinda retarded seeing that the basefilter works this way.

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

It's not retarded at all, actually it could be a good idea (it would make a 'cleaner' API).
But it would not be possible (or easy) to implement a solution for searching on lists so dynamic like it is today.
Also, I would like to support other kind of data engines (NoSQL) in the future, this solution makes an abstraction layer that make it possible.

Never feel bad to propose, question or brainstorm, even if you get it wrong. Actually your comments made me think about supporting model joins, and question about the API in general.

from flask-appbuilder.

ben-github avatar ben-github commented on May 3, 2024

I don't have much to add, but would enjoy this feature as well. For my purposes, here's the work-around I did.

Table A has two columns that are a composite Foreign key to two columns in Table B. When adding an entry to Table A, the two foreign columns are treated independently by Flask-AppBuilder (using somewhat tricky relationships in the model.py definition) so can select
("X,only-works-with-Y") instead of ("Y,only-works-with-Y"). But when you do the insert, the db foreign key rejects what doesn't work so at least you know -- hopefully the end user knows what combination are valid. Not ideal but functional.

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

I noticed their was some work already done on this.
I have taken another stab at this and realized there would need to be some larger changes. Namely select2 fields would get all their data via ajax.
The filled in form is serialized and passed to the ajax request so that it can be used in the query.
This means the cascade filter can be added. Plus a user can overload the ajax request method and do whatever they want with it.
I will make a pull request when I done.

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

Careful with turning all select2 to ajax, search widget uses it. This is a tricky one...

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

Yes it is turning out to be rather tricky. I have the base set up, But now trying to make sure all those self.add_form.refresh calls don't reset the dynamically set form choices not allowing the form.validate() to succeed. Plus ensuring all the existing base filters work. While trying to continue working only through the datamodel and filters api to ensure everything else works for other db's.

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

If you need any help, don't hesitate.

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

Sorry for taking long. I have this feature for the standard ModelViews. But the search widgets are still a problem. What is the best approach to fixing this is?
If you want you can see the changes in my fork.
https://github.com/philliproso/Flask-AppBuilder/tree/ajax_select_2

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

No problem

Lot of work here, with some major changes. I need to carefully look at this...

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

Looking back, I think it is best to simply show an example of how to create this feature using a custom widget, an additional form field, overloading the pre_add method and the add and edit template.

This would have minimum impact on the existing code base. Currently what I have done in my fork is a bit too disruptive. However I think long term all select 2's should be moved to ajax style requests, and the filters module could probably do with some simplification.

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

Looks great could you write a little tutorial on the docs about this?

from flask-appbuilder.

philliproso avatar philliproso commented on May 3, 2024

I will create an example and make a pull request just for the example

from flask-appbuilder.

dpgaspar avatar dpgaspar commented on May 3, 2024

Great, Thanks.

from flask-appbuilder.

scheung38 avatar scheung38 commented on May 3, 2024

This talks about it here

http://librelist.com/browser/flask/2012/10/3/populating-forms-based-on-initial-entry/#00bf3feb9757706a4254b0e3596a2159

But I am not sure if compatible with Flask-AppBuilder

from flask-appbuilder.

jvinolas avatar jvinolas commented on May 3, 2024

And with a little of ajax? You have to expose /filtrarplantilla/
(haven't test it in appbuilder, but works with Flask)

function filtrarPlantillaTipus(element) {
    var tipus = element.options[element.selectedIndex].value
    var llista = document.getElementById("VMTemplate")
    $.ajax({
        type: "GET",
        //~ dataType: "json",
        url:"/filtraPlantilla/" + tipus,
        success: function(templates)
        {
            if (templates.length >0) {
                var contingut='<option value="">Seleccioneu una entre '+templates.length+' plantilles trobades</option>';
            } else {
                var contingut='<option value="">Cap plantilla coincident</option>';                     
            }
          for (var i=0; i<templates.length; i++) {
                contingut=contingut+'<option value="'+templates[i]['id']+'" >'+templates[i]['name']+'</option>';
            }
          llista.innerHTML=contingut;
        }               
    });

And then in your template:

            <tr>
                <td>Tipus de plantilla:</td>
                <td><select name="VMTemplateType" onchange="filtrarPlantillaTipus(this);">
                        <option value="">Seleccioneu tipus de plantilla:</option>
                        <option value="VIMET">vimet</option>
                        <option value="MEVES">Meves</option>
                        <option value="PUBLIQUES">Públiques</option>
                        </select>
                </td>
            <tr>
                <td>Plantilla:</td>
                <td><select id="VMTemplate" name="VMTemplate" onchange="selectChange(this);">
                        <option value="">Seleccioneu plantilla base:</option>
                </td>
            <tr>

from flask-appbuilder.

jvinolas avatar jvinolas commented on May 3, 2024

Hi again,

One option will be to override the add.html template to add your own javascript code and find what is the id for the html select block. For example:

                <select class="my_select2 form-control" data-placeholder="Select Value" id="template_base" name="template_base" style="width:250px"></select>

That in your example will be dummy_city2 or something like that.

But you should call filtrarPlantillaTipus on the first select (location) so I think the only way will be to create your own select widget that calls that function onchange.

This is only an idea.

from flask-appbuilder.

scheung38 avatar scheung38 commented on May 3, 2024

Hi Jvinolas,

I have overriden add.html in my views.py:

class MyGeneralView(ModelView):
datamodel = SQLAInterface(MyDataBase)
add_template = 'add_contacts.html'

Then in my templates/add_contacts.html:

{% extends "appbuilder/general/model/add.html" %}
{% block add_form %}
{{ super() }}
"""

Welcome

This Text is before the add form widget
"""
{% endblock %}

But trying to work out how to do what you suggested.

BTW is your syntax above correct? tr don't seem to have closing tags?

And how to expose /filtrarplantilla/? I do have Flask-Restless so maybe in init.py:

api_manager = APIManager(app, flask_sqlalchemy_db=db)
api_manager.create_api(Countries, methods=['GET', 'POST', 'DELETE', 'PUT'])

create one more for localhost:8080/api/filtrarplantilla/
api_manager.create_api(xxx?, methods=['GET', 'POST', 'DELETE', 'PUT'])

And where to place that statement:

select class="my_select2 form-control" data-placeholder="Select Value" id="template_base" name="template_base" style="width:250px">

from flask-appbuilder.

scheung38 avatar scheung38 commented on May 3, 2024

http://devzone.co.in/simple-example-of-dependable-dropdowns-cascading-dropdowns-using-angularjs/

Also, doesn't seem to work above angularJS > 1.0.8 when current stable release is 1.3.15.

in views.py:
class MgntServerGeneralView(ModelView):
datamodel = SQLAInterface(MyTable)
add_template = 'testDropDown.html'

/templates/testDropDown.html:

<title>Cascading Dropdowns in AngularJs :devzone.co.in </title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script> <script> function CountryCntrl($scope) { $scope.countries = { 'India': { 'Maharashtra': ['Pune', 'Mumbai', 'Nagpur', 'Akola'], 'Madhya Pradesh': ['Indore', 'Bhopal', 'Jabalpur'], 'Rajasthan': ['Jaipur', 'Ajmer', 'Jodhpur'] }, 'USA': { 'Alabama': ['Montgomery', 'Birmingham'], 'California': ['Sacramento', 'Fremont'], 'Illinois': ['Springfield', 'Chicago'] }, 'Australia': { 'New South Wales': ['Sydney'], 'Victoria': ['Melbourne'] } }; } </script>
    <div ng-controller="CountryCntrl">
        <div>
            Region:
            <select id="country" ng-model="states" ng-options="country for (country, states) in countries">
                <option value=''>Select</option>
            </select>
        </div>
        <div>
            Cities: <select id="state" ng-disabled="!states" ng-model="cities" ng-options="state for (state,city) in states"><option value=''>Select</option></select>
        </div>
    </div>

</body>

in app.js:

function CountryCntrl($scope) {
$scope.countries = {
'India': {
'Maharashtra': ['Pune', 'Mumbai', 'Nagpur', 'Akola'],
'Madhya Pradesh': ['Indore', 'Bhopal', 'Jabalpur'],
'Rajasthan': ['Jaipur', 'Ajmer', 'Jodhpur']
},
'USA': {
'Alabama': ['Montgomery', 'Birmingham'],
'California': ['Sacramento', 'Fremont'],
'Illinois': ['Springfield', 'Chicago']
},
'Australia': {
'New South Wales': ['Sydney'],
'Victoria': ['Melbourne']
}
};
}

But this doesn't tie in with Flask-AppBuilder SQLAlchemy with look and feel and database.

from flask-appbuilder.

scheung38 avatar scheung38 commented on May 3, 2024

So is it a challenge to implement in Flask-AppBuilder? Or is it quite straight forward to add, say AngularJS logic to the front end by overriding select widget?

from flask-appbuilder.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.