невозможно больше перетаскивать в fullcalendar, когда фильтр применяется к внешним событиям - PullRequest
0 голосов
/ 26 января 2019

Я пытаюсь перетащить события из окна внешних событий в полный календарь.

Я воссоздал проблему, с которой сталкиваюсь, в следующем CodePen :

вВ первый раз перетаскивание внешнего события из списка в календарь работает нормально.Однако, когда я применяю фильтр к книге в текстовом фильтре книг поиска ввода, у меня возникает следующая проблема:

Вот шаги для воспроизведения:

1 - ищите 111 в поискевходные данные, которые будут фильтроваться в единственную полученную книгу событий 111.

2- Как вы могли заметить, перетаскивание этого результирующего события из фильтра в календарь может работать нормально: но здесь нас интересует, в основном, случай, который мы решилифильтровать, но не перетаскивать что-либо в календарь.

3- так что пока удалите фильтр 111 как текст из входных данных поиска, поле внешних событий вернет все события по умолчанию, но на этот раз при попытке перетащить одиниз них в календарь зависает.Он больше не работает.
Он останавливается на всех внешних событиях , за исключением для . Последнее найденное фильтром означает событие 111 (посмотрите последнюю строку насобытия) тот единственный, который можно перетащить.и больше не сможет перетаскивать другие события в календарь.

4- и даже если я перетащу 111 в календарь, и после этого, если я попытаюсь перетащить еще один, он замерзнет.

HTML

<!DOCTYPE html>
<html ng-app="app">
  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <script data-require="angular.js@1.0.x" src="https://code.angularjs.org/1.3.15/angular.min.js" data-semver="1.0.7"></script>
    <script type="text/javascript" src="https://github.com/kamilkp/angular-vs-repeat/blob/master/dist/angular-vs-repeat.js"></script>
    <script src="https://code.angularjs.org/1.3.15/angular-animate.min.js"></script>
  </head>
<body ng-controller="MainCtrl">
<div id="first">
             <input type="search" id="myInput" ng-model="searchText" placeholder="filter books..." title="filter books"/>
             <div style="width:200px;display:inline-block;vertical-align:top;color: gray;">
                    <input type='checkbox' id='drop-remove' checked='checked'/>
                    <label for='drop-remove'> Remove after a drag </label>
             </div>
 <div id='external-events'>

             <ul vs-repeat="60" class="repeater-container" title="Books darggable({{books.length}})" data-                        drag="true"  data-jqyoui-options="{revert: 'invalid'}">
                 <li class="animate-repeat fc-event item-element" ng-repeat="book in books | orderBy : sort : false | filter:searchText as results track by book.contents.name"   id="{{book.id}}">

                   <div class="circle">{{book.contents['date']}}</div>
                   <div class="left content" ng-bind-html="trustAsHtml(book.contents['name'])" id="book_{{book.id}}"></div>
                   <div class="left rating">2/10</div>
                   <div class="clear"></div>
                </li>
                <li class="animate-repeat" ng-if="results.length === 0">
                    <strong>No results found...</strong>
                </li>

             </ul>
  </div>
</div>

<div id="second"> 
  <div id='calendar-container'>
    <div id='calendar'></div>
  </div>
</div>
</body>
</html>

js

var app = angular.module("app", ['ngAnimate']);
(function(angular) {
  'use strict';
app.controller("MainCtrl", ['$scope', '$sce', function($scope, $sce){

 $scope.books = [
                {
                    id: 'id1',
                    contents: {
                        name: '<span>1Alain du sceau france</span><br><span> Canada Madagascar philipine</span>',
                        price: 'price1',
                        date: '111'
                    }
                },
                {
                    id: 'id2',
                    contents: {
                        name: '<span>2Name zu Long zu Schreiben Bis Here ist Ein Beispiel</span><br><span>Maneschester Canada Madagascar philipine</span>',
                        price: 'price2',
                        date: '22'
                    }
                },
                {
                    id: 'id3',
                    contents: {
                        name: '<span>3name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price3',
                        date: '23'
                    }
                },
                {
                    id: '4',
                    contents: {
                        name: '<span>4name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price4',
                        date: '4'
                    }
            },
            {
                    id: 'id5',
                    contents: {
                        name: '<span>5name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price5',
                        date: '5'
                    }
            },
            {
                    id: 'id6',
                    contents: {
                        name: '<span>6name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price6',
                        date: '6'
                    }
            },
            {
                    id: 'id7',
                    contents: {
                        name: '<span>7name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price7',
                        date: '7'
                    }
            },
            {
                    id: 'id8',
                    contents: {
                        name: '<span>8name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price8',
                        date: '8'
                    }
            },
            {
                    id: 'id9',
                    contents: {
                        name: '<span>9name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price9',
                        date: '9'
                    }
            },
               {
                    id: 'id10',
                    contents: {
                        name: '<span>10Alain du sceau france</span><br><span> Canada Madagascar philipine</span>',
                        price: 'price10',
                        date: '10'
                    }
                },
                {
                    id: 'id11',
                    contents: {
                        name: '<span>11Name zu Long zu Schreiben Bis Here ist Ein Beispiel</span><br><span>Maneschester Canada Madagascar philipine</span>',
                        price: 'price11',
                        date: '11'
                    }
                },
                {
                    id: 'id12',
                    contents: {
                        name: '<span>12name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price12',
                        date: '12'
                    }
                },
                {
                    id: 'id13',
                    contents: {
                        name: '<span>13name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price13',
                        date: '13'
                    }
            },
            {
                    id: 'id14',
                    contents: {
                        name: '<span>14name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price14',
                        date: '14'
                    }
            },
            {
                    id: 'id15',
                    contents: {
                        name: '<span>15name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price15',
                        date: '15'
                    }
            },
            {
                    id: 'id16',
                    contents: {
                        name: '<span>16name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price16',
                        date: '16'
                    }
            },
            {
                    id: 'id17',
                    contents: {
                        name: '<span>17name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price17',
                        date: '17'
                    }
            },
            {
                    id: 'id18',
                    contents: {
                        name: '<span>18name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price18',
                        date: '18'
                    }
            },
            {
                    id: 'id19',
                    contents: {
                        name: '<span>19name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price19',
                        date: '19'
                    }
            },
            {
                    id: 'id20',
                    contents: {
                        name: '<span>20name Aleatoire Schwer und zu Leicht Zu Schreiben</span><br><span>Mexico Canada USA France Uk Deutschland Schweiz Madagascar philipine</span>',
                        price: 'price20',
                        date: '20'
                    }
            }
            ];





  /*$scope.books.forEach(function(book) {
    book.contents.name =  $sce.trustAsHtml(book.contents.name);
  })*/
  $scope.trustAsHtml = $sce.trustAsHtml;

  $scope.h = function(html) {
    return $sce.trustAsHtml(html);
  };

  $scope.sort = function(num) {
    var newNum = parseInt(num.contents.date);
    console.log("$$newnum",newNum);
    return newNum;
  };


 $(document).ready( function(){     
        //Initialise external events
        initialise_external_event('.fc-event');
        initialise_calendar();

  });





  // initialize the external events
  // -----------------------------------------------------------------
function initialise_external_event(selector){

   /* initialize the external events
        -----------------------------------------------------------------*/

        $('#external-events .fc-event').each(function() {

            // store data so the calendar knows to render an event upon drop
            $(this).data('event', {
                title: $.trim($(this).text()), // use the element's text as the event title
                stick: true // maintain when user navigates (see docs on the renderEvent method)
            });

            // make the event draggable using jQuery UI
            $(this).draggable({
                zIndex: 999,
                revert: true,      // will cause the event to go back to its
                revertDuration: 0  //  original position after the drag
            });

        });



}
  function initialise_calendar(){
     /* initialize the calendar
        -----------------------------------------------------------------*/

        $('#calendar').fullCalendar({
            header: {
                left: 'prev,next today',
                center: 'title',
                right: 'month,agendaWeek,agendaDay'
            },
            editable: true,
            droppable: true, // this allows things to be dropped onto the calendar
            dragRevertDuration: 0,
            drop: function() {
                // is the "remove after drop" checkbox checked?
                if ($('#drop-remove').is(':checked')) {
                    // if so, remove the element from the "Draggable Events" list
                    $(this).remove();
                }
            },
            eventDragStop: function( event, jsEvent, ui, view ) {

                if(isEventOverDiv(jsEvent.clientX, jsEvent.clientY)) {
                    $('#calendar').fullCalendar('removeEvents', event._id);
                    var el = $( "<div class='fc-event'>" ).appendTo( '#external-events-listing' ).text( event.title );
                    el.draggable({
                      zIndex: 999,
                      revert: true, 
                      revertDuration: 0 
                    });
                    el.data('event', { title: event.title, id :event.id, stick: true });
                }
            }
        });


        var isEventOverDiv = function(x, y) {

            var external_events = $( '#external-events' );
            var offset = external_events.offset();
            offset.right = external_events.width() + offset.left;
            offset.bottom = external_events.height() + offset.top;

            // Compare
            if (x >= offset.left
                && y >= offset.top
                && x <= offset.right
                && y <= offset .bottom) { return true; }
            return false;

        }
 }

}]);
})(window.angular);

css

    ul[title]::before {

    content: attr(title);
     /* then add some nice styling as needed, eg: */

     font: italic 11px "Trebuchet MS", Verdana, Arial, Helvetica,    sans-serif;
    color: gray;
}

/*ul {
  list-style-type: none;
}*/

#myInput {
  /*background-image: url('/css/searchicon.png');*/
  background-position: 10px 12px;
  background-repeat: no-repeat;
  width: 77%;
  font-size: 16px;
  padding: 12px 20px 12px 40px;
  border: 1px solid #ddd;
  margin-bottom: 12px;
}

/*ul>li {
  display:block;
    padding-right: 0cm;
    margin-left: 0px;
}*/

#calendar{
 padding: 0 10px;
 width: 650px;
 float: right;
 margin: 0px 0px 10px 55px;
 }

#external-events {
  width: 500px;
  padding: 0 0px;
  border: 0px solid #ccc;/* gray moyen*/
  background: #eee;/* #5D6D7E;(Blue mat) */ /* #eee color gray*/
  text-align: left;
}

#external-events .fc-event {
  cursor: pointer;
  z-index: 9999;
  background: #eee;
  border: solid 1px black;
  border-radius: 2px;
  margin-bottom:5px;
}

.content span
{
  color: gray;
}
.fc-event span:first-child
{
  font-size: 25px;
  font-weight: bold italic;
}

.content
{
  float:left;
  max-width:75%;
}

.clear
{
  clear:both;
}

.circle {
  float:left;
  width: 10%;
  height: 25%;
  padding: 0 10px;
  border-radius: 360px;


  /* Just making it pretty */
  @shadow: rgba(0, 0, 0, .1);
  @shadow-length: 4px;
  -webkit-box-shadow: 0 @shadow-length 0 0 @shadow;
          box-shadow: 0 @shadow-length 0 0 @shadow;
  text-shadow: 0 @shadow-length 0 @shadow;
  background: #FFFFFF;/*color white*/
  color: #f05907;/* color red*/
  font-family: Helvetica, Arial Black, sans;
  font-size: 10;
  text-align: center;
}

.rating
{
  float:right;
  background: #FFFFFF;/*color white*/
  color: #f05907;/* color red*/
  font-family: Helvetica, Arial Black, sans;
  font-size: 10;
  text-align: center;
  border-radius: 360px;
}

.animate-repeat {
  line-height:30px;
  list-style:none;
  box-sizing:border-box;
}

.animate-repeat.ng-move,
.animate-repeat.ng-enter,
.animate-repeat.ng-leave {
  transition:all linear 0.5s;
}

.animate-repeat.ng-leave.ng-leave-active,
.animate-repeat.ng-move,
.animate-repeat.ng-enter {
  opacity:0;
  max-height:0;
}

.animate-repeat.ng-leave,
.animate-repeat.ng-move.ng-move-active,
.animate-repeat.ng-enter.ng-enter-active {
  opacity:1;
  max-height:30px;
}


#first {
    width: 650px;
    float: left
}
#second {
    width: 650px;
    float: left;
}


.repeater-container{
  height: 445px;
  overflow: auto;
  box-shadow: 0 0 10px;
  border-radius: 5px;
  list-style: none;
  margin: 0;
  padding: 0;
  -webkit-overflow-scrolling: touch;
}
.repeater-container .item-element {
    margin: 0 !important;
    width: 100%;
    height: 140px;
    border: 1px solid green;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
}

1 Ответ

0 голосов
/ 28 января 2019

нг-повтор с фильтром воссоздающих предметов DOM.

То, что не должно быть сделано (Как видно из моего кода в HTML, я использую ng-repeat с track by book.contents.name и насколько я знаю в

в этом случае angularjs не восстановит дом. В противном случае, если мы используем

ng-repeat без трека по id angularjs воссоздает дом, которого вы могли видеть THE_FOLOWING_LINK ).

Мне довольно сложно понять, почему именно дом

воссоздается в этом случае с помощью ng-repeat с фильтром!

Обходной путь, который я сделал, описан в тексте ниже:

1- Итак, чтобы снова сделать предмет перетаскиваемым, нужно позвонить .draggable () для каждого действия фильтра.

Идеальным решением является манипулирование DOM в угловом положении. директива через функцию связи. но здесь, чтобы сделать вещи намного проще обходной путь, который я только что включил в DetectEmpty, который является функцией с ограничением.

2 - добавлено ng-change = "detectEmpty ()", чтобы определить, когда очищается вход

<input type="search" id="myInput" ng-model="searchText" placeholder="filter books..." title="filter books" ng-change="detectEmpty()"/>

3- и .js

$scope.detectEmpty = function() {
    if ($scope.searchText.trim().length === 0) {
         // it's empty
        $(document).ready( function(){     


           initialise_external_event('.fc-event');

        });

    }

Let's try to understand what's going on here?
=============================================
- All html elements loaded first.
- JS trigger all dragging functionality to loaded DOM.
- ng-repeat with filter function call to fetch new data and replace old 
  DOMs.
- Now drag functionality stops working.
- why? because JS drag function run on old DOM and currently it has been 
  removed. **why it has been moved ? I don't have any clue on that**
 - need to call the drag function again on new loaded DOM.
 - that's why added the call to initialise_external_event('.fc-event');
   when the input search is cleared. 

Надеюсь, это поможет кому-то еще;)

Надеюсь, также AngularJS pro расскажет нам, почему в этом случае воссоздан дом?

Обновление

потому что предлагаемое решение раньше - плохое решение.

путем повторной инициализации внешних событий каждый раз, когда фильтр применяется следующим образом:

$scope.detectEmpty = function() {
        if ($scope.searchText.trim().length === 0) {
             // it's empty
            $(document).ready( function(){     


               initialise_external_event('.fc-event');

            });

        }

будет добавлять каждый раз дополнительное внешнее событие в поле внешних событий. Если мы начнем, например, с массива из 20 записей, мы получим 40 при следующем применении фильтра и добавим 20 записей в наши записи массива exteranl при каждом применении фильтра. 20,40,60,80 и т. Д.

Вопрос в том, как сохранить элементы DOM при использовании ng-repeat с фильтром?

У меня есть нг-повтор с фильтром.

Когда некоторые элементы отфильтровываются фильтром, а затем они восстановлены после другой замены фильтра там новые элементы DOM, созданные для этих элементов.

Если была какая-либо манипуляция DOM с предметом, он теряется после Предмет скрыт и восстановлен с помощью фильтра.

Есть ли способ сохранить элементы DOM, даже если элемент удален фильтром?

Я пытался использовать трек, по которому следовал LINK , но это не помогло.

1- Так, чтобы посмотреть изменение DOM и подтвердить это. Вы можете использовать следующую ссылку и воспользоваться услугой от Basheer AL-MOMANI

2- Корень проблемы в том, что я пытаюсь сделать это вне угла. Делая все в пределах angular, angular будет обновлять DOM для нас по мере необходимости.

Если у нас сложный код манипуляции с DOM, похоже, нам нужна директива для этого. Затем мы просто прикрепляем директиву к этим элементам, и DOM будет обновляться по желанию. и для получения более подробной информации об этом смотрите следующую ссылку и эту [JSFIDDLE]

4 , что связано с ответом.

3- Мы также должны попытаться реализовать календарь перетаскивания с угловыми директивами. Для этого мы используем JqueryUI Draggable. Создавая директиву и передавая атрибуты через "elem".

directive('dragMe', function() {
  return {
    restrict: 'A',
    link: function(scope, elem, attr, ctrl) {
      elem.data('event', {
          title: $.trim($(elem).text()), // use the element's text as the event title
          stick: true // maintain when user navigates (see docs on the renderEvent method)
        });
      elem.draggable({
          zIndex: 999,
          revert: true,      // will cause the event to go back to its
          revertDuration: 0  //  original position after the drag
        });
    }
  };
})

и добавляем сюда drag-me:

<li class="animate-repeat fc-event  item-element" drag-me    
ng-repeat="book in books | orderBy : sort : false  | filter: searchText as results track by book.id"   id="{{book.id}}"
 >                   

С другой стороны, у меня есть элемент, который я связываю с ним html.

См. vkammerer ответ по этой ссылке

и мы добавляем compile = "book.contents.name"

Здесь пересмотрено. Working CodePen , который работает с директивами для обработки добавления, перетаскиваемого на наши элементы каждый раз, когда применяется ng-repeat с фильтром.

Надеюсь, это поможет кому-то еще;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...