-->

Codemirror content not visible in bootstrap modal

2020-08-09 09:20发布

问题:

I am using codemirror 3 with bootstrap. In my bootstrap modal, there is a textarea, and i am replacing it with codemirror. I am using task_name_editor.setValue('initial value') to initialise codemirror with an input. The problem is that the content is there, but it is not visible until it is clicked or any key is pressed while it is focused.

I tried Marijn's answer to a similar question, but i don't know where to place task_name_editor.refresh()

I tried placing it where i show the modal -

$('#edit_task_modal').modal('show');
task_name_editor.setValue('initial value');
task_name_editor.refresh();

even then, it is not working Please can anyone show how to fix this problem ?

回答1:

A cleaner solution perhaps?

Bootstrap modals have an event that fires after the modal is shown. In Bootstrap 3, this is shown.bs.modal.

modal.on('shown.bs.modal', function() {
    // initialize codemirror here
});


回答2:

You can now use the Code Mirror addon Auto Refresh: https://codemirror.net/doc/manual.html#addon_autorefresh

Just include the script dependency

<script src="../display/autorefresh.js" %}"></script>
Which now gives you the option "autoRefresh" to auto refresh just once right after displaying the content.
var myCodeMirror = CodeMirror.fromTextArea(myTextArea,{
  autoRefresh: true,
});

The docs also state its a 250ms time delay after showing the hidden content. You can increase that delay if you are loading a lot of content.



回答3:

I figured it has something to do with viewport size change while tabs are hidden and shown again. So the following worked for me:

1) Listen for clicks over the tabs 2) On click, call refresh() on all CM editors or just the one inside a tab, as you prefer

It's important to note that refresh() must be called with a small time-out, otherwise in some browsers (i got this in Chrome), the editor is displayed, but with some invalid offsets.

Try something like this:

$(document).ready(function() {
    $("#your_nav_tabs a").click(function(e) {
        if(window.codeMirrorInstances != null) { // window.codeMirrorInstances must be initialized and tracked manually
            $.each(window.codeMirrorInstances, function(index, cm) {
                setTimeout(function() {
                    cm.refresh();
                }, 100);
            });
        }

        return false;
    });
});


回答4:

With help from this question, I was able to get a CodeMirror editor, which was sitting in an inactive bootstrap 3 tab and therefore not completely initialized, and refresh it when the tab is clicked. Maybe someone finds it useful.

Coffeescript version:

$('a[data-toggle="tab"]').on 'shown.bs.tab', (e) ->
  target = $(e.target).attr("href") # activated tab
  $(target + ' .CodeMirror').each (i, el) ->
    el.CodeMirror.refresh()


回答5:

If you initialize editor on modal shown event, problem will be solved. Just put this script on parent page.

$('#myModal').on('shown', function () {
    CodeMirror.fromTextArea(document.getElementById('MyTextArea'), { mode: 'xml', lineNumbers: true });
});


回答6:

I'm having a similar issue with regards to bootstrap in general (not specifically with modals). However, my solution was to make sure I created the codemirror editor as early as possible (rather than on the document's ready event). I'm guessing this has something to do with the way bootstrap calculates the widths and heights in the grid.

<body>
    <!-- my page content -->

    <script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>

    <script type="text/javascript">
        // Create the code editor here rather than on document.ready
        editor = CodeMirror(...);
    </script>
</body>


回答7:

I was having a very similar problem with CodeMirror: if it was initialized while it wasn't the active bootstrap tab, it wouldn't show any content. My workaround was the opposite from @pbergqvist - to initialize the CodeMirror control as late as possible, i.e., after the tab in question was selected. Using TypeScript, it looks kind of like this:

var tabClicked = $.Deferred();
$('#scriptTab').click(() => tabClicked.resolve());
$.ajax('/api/script')
    .done(script => {
        this.tabClicked.done(() => {
            setTimeout(()=> {
                var codeMirror = CodeMirror.fromTextArea($('#script')[0]);
                codeMirror.getDoc().setValue(script);
            }, 10);
        });
    })
    .fail(err=> console.error('Error retrieving script: ' + JSON.stringify(err)));

Hope this helps someone.



回答8:

(angular,bootstrap) I just solved it with a simple timeout, like this:

<button class="btn btn-default pull-right margin" data-toggle="modal" data-target="#codesnippetmodal" ng-click="getcodesnippet(module)">
 open modal
</button>

and then in my controller:

$scope.getcodesnippet = function(module) {
    var clientmodule = {
        clientid: $rootScope.activeclient.id,
        moduleid: module.id
    }
    Data.post('getCodesnippet', {
        clientmodule: clientmodule
    }).then(function(results) {

        codesnippet_editor.setValue(results.codesnippet);
        setTimeout(function() {
            codesnippet_editor.refresh();
        }, 500);
    });
}


回答9:

to avoid getting refreshed every time (meaning position and changes lost) i strongly advise for using like this:

$('#meinetabs a[data-toggle="tab"]').on('shown.bs.tab', function (e) 
{
    if (var5 !=="5")
         {
            editor_htaccess.refresh();
         }
    var5 = "5";
})  

Its under MIT license because i am such a nice person