admin管理员组

文章数量:1426066

I'm using Vue.js 2.1.10 and Bootstrap 3.3.7 to show a modal that opens another modal dialog. Each modal dialog is contained in a distinct ponent. Inside the 1st ponent, there is a reference to the 2nd ponent (select-travler).

According to the Bootsrap documentation, I have to set the focus by listening to the event shown.bs.modal. This works great to set the focus on an input control contained in the 1st modal. Problem: this way doesn't work when the modal is above another modal.

The 1st modal ponent looks like this:

<template>
    <div ref="tripEdit" class="modal fade" role="dialog">
        <!-- Inbeded ponent -->
        <select-travler ref="selectTravler"></select-travler>
        <!-- /Inbeded ponent -->

        <div class="modal-lg modal-dialog">
            <div class="modal-content">
                <div class="modal-body container form-horizontal">

                    <div class="form-group">
                        <label for="travler_name" class="control-label">
                            Travler's name
                        </label>
                        <input id="travler_name" ref="travler_name"
                            v-model="travler_name"/>
                    </div>
                </div>
            </div>
        </div>

    </div>
</template>

<script>
    export default {
        data () {
            return {
                travler_name: null,
            }
        },

        methods: {
            show (operationType) {
                $(this.$refs.tripEdit).modal('show');

                let that = this;
                $(this.$refs.tripEdit).on('shown.bs.modal', function () {
                    $(that.$refs.travler_name).focus();
                });

                if (operationType === 'newTravel') {
                    this.$refs.selectTravler.show();
                }
            },            
        },
    }
</script>

The 2nd ponent contains a similar layout with the following show method:

show () {
    $(this.$refs.selectTravler).modal('show');

    let that = this;
    $(this.$refs.selectTravler).on('shown.bs.modal', function () {
        $(that.$refs.people_names).focus();
    });
},

When the 2nd modal opens, the focus is still on the 1st modal behind the 2nd modal dialog (I can see the caret blinking in travler_name). How can I set the focus on people_names when the 2nd modal is shown?

I'm using Vue.js 2.1.10 and Bootstrap 3.3.7 to show a modal that opens another modal dialog. Each modal dialog is contained in a distinct ponent. Inside the 1st ponent, there is a reference to the 2nd ponent (select-travler).

According to the Bootsrap documentation, I have to set the focus by listening to the event shown.bs.modal. This works great to set the focus on an input control contained in the 1st modal. Problem: this way doesn't work when the modal is above another modal.

The 1st modal ponent looks like this:

<template>
    <div ref="tripEdit" class="modal fade" role="dialog">
        <!-- Inbeded ponent -->
        <select-travler ref="selectTravler"></select-travler>
        <!-- /Inbeded ponent -->

        <div class="modal-lg modal-dialog">
            <div class="modal-content">
                <div class="modal-body container form-horizontal">

                    <div class="form-group">
                        <label for="travler_name" class="control-label">
                            Travler's name
                        </label>
                        <input id="travler_name" ref="travler_name"
                            v-model="travler_name"/>
                    </div>
                </div>
            </div>
        </div>

    </div>
</template>

<script>
    export default {
        data () {
            return {
                travler_name: null,
            }
        },

        methods: {
            show (operationType) {
                $(this.$refs.tripEdit).modal('show');

                let that = this;
                $(this.$refs.tripEdit).on('shown.bs.modal', function () {
                    $(that.$refs.travler_name).focus();
                });

                if (operationType === 'newTravel') {
                    this.$refs.selectTravler.show();
                }
            },            
        },
    }
</script>

The 2nd ponent contains a similar layout with the following show method:

show () {
    $(this.$refs.selectTravler).modal('show');

    let that = this;
    $(this.$refs.selectTravler).on('shown.bs.modal', function () {
        $(that.$refs.people_names).focus();
    });
},

When the 2nd modal opens, the focus is still on the 1st modal behind the 2nd modal dialog (I can see the caret blinking in travler_name). How can I set the focus on people_names when the 2nd modal is shown?

Share Improve this question asked Aug 10, 2017 at 15:01 WarrioWarrio 1,9135 gold badges29 silver badges46 bronze badges 1
  • It looks to me like you are adding new shown.bs.modal handlers every time a modal is shown, and more than that, you're adding them after the modal is triggered to be shown. You probably want to move the .on(...) code into the mounted event. Also, don't forget to remove the handler when the modal is destroyed. – Bert Commented Aug 10, 2017 at 15:26
Add a ment  | 

3 Answers 3

Reset to default 5

I think there are really several issues at play here. First, as I mentioned in the ment above, you are not properly adding and removing the shown.bs.modal event handlers.

Second, because your second modal is nested inside the first modal, the shown.bs.modal event will bubble up to the parent modal and it's handler will fire. Initially I thought stopPropagation would be a good way to handle this, but in the end, I simply de-nested the submodal ponent in the template.

Here is an example of this behavior actually working.

console.clear()

Vue.ponent("sub-modal", {
  template: "#submodal",
  methods: {
    show() {
      $(this.$el).modal("show")
    },
    onShown(event) {
      console.log("submodal onshown")
      this.$refs.input.focus()
    }
  },
  mounted() {
   $(this.$el).on("shown.bs.modal", this.onShown)
  },
  beforeDestroy() {
    $(this.$el).off("shown.bs.modal", this.onShown)
  }
})

Vue.ponent("modal", {
  template: "#modal",
  methods: {
    show() {
      $(this.$refs.modal).modal("show")
    },
    showSubModal() {
      this.$refs.submodal.show()
    },
    onShown(event) {
      console.log("parent")
      this.$refs.input.focus()
    }
  },
  mounted() {
    $(this.$refs.modal).on("shown.bs.modal", this.onShown)
  },
  beforeDestroy() {
    $(this.$refs.modal).off("shown.bs.modal", this.onShown)
  }
})

new Vue({
  el: "#app",
})
<link href="https://cdnjs.cloudflare./ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />


<script src="https://unpkg./[email protected]/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div id="app">
  <modal ref="modal"></modal>
  <button @click="$refs.modal.show()" class="btn">Show Modal</button>
</div>

<template id="submodal">
  <div class="modal fade" tabindex="-1" role="dialog">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
          <h4 class="modal-title">Modal title</h4>
        </div>
        <div class="modal-body">
          <input ref="input" type="text" class="form-control">
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
          <button type="button" class="btn btn-primary">Save changes</button>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
  </div><!-- /.modal -->

</template>

<template id="modal">
  <div>
    <div ref="modal" class="modal fade" tabindex="-1" role="dialog">

      <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title">Modal title</h4>
          </div>
          <div class="modal-body">
            Stuff
            <input ref="input" type="text" class="form-control">
          </div>
          <div class="modal-footer">
            <button @click="showSubModal" type="button" class="btn btn-primary">Show Sub Modal</button>
          </div>
        </div><!-- /.modal-content -->
      </div><!-- /.modal-dialog -->
    </div><!-- /.modal -->
    <sub-modal ref="submodal"></sub-modal>
  </div>
</template>

Also, for future readers, I got some useful information about how to construct the template for the modal ponent used above from this answer. Specifically, unless you manually specify a z-index for the modal, the modal that appears last in HTML will have a higher z-index. The implication being the submodal ponent needs to e second in the template.

I ran into a similar issue. A b-modal forces focus to stay in the modal. You can disable it by adding a no-enforce-focus attribute.

no-enforce-focus Boolean false Disables the enforce focus routine which maintains focus inside the modal

https://bootstrap-vue/docs/ponents/modal

This means that the element you're trying to focus is not properly referenced. Trying to console.log(element); the line before focussing people_names. To see if you're getting the right element.

show () {
    $(this.$refs.selectTravler).modal('show');

    let element = this.$refs.people_names;
    $(this.$refs.selectTravler).on('shown.bs.modal', function () {
        $(element).focus();
    });
},

Have you considered v-show to open and close your modals ?

本文标签: javascriptSet focus on a input control contained in a second level bootstrap modalStack Overflow