Клуб API Карт

Правильная работа с контентом балуна

Пост в архиве.

Здравствуйте. У меня пару вопросов по поводу изменения контента балуна, что-то похожее я нашёл в темах, но не совсем...

И так, на карте имеется набор меток, для каждой из них имеется балун:

 

 var placemark = new ymaps.Placemark([markerArray.latitude, markerArray.longitude],

   {

     id: markerArray.ID_marker, 

     cost: markerArray.cost == 1 ? true : false,

     type: markerArray.type == 1 ? true : false, 

     i_was: markerArray.i_was, 

     people_was: markerArray.people_was,

     uStat: $('#bulion').val() ? true : false

   }

);

self.markersCollection.add(placemark);

 

var balloonLayout = ymaps.templateLayoutFactory.createClass(

             '<div class="ball-content" id="$[properties.id]">' +

                  '<div class="statuses">' +

                     '<div class="color-status [if properties.cost]fee">Условие1[else]free">Условие2[endif]</div>' +

                     '<div class="color-status [if properties.type]out">Условие1[else]in">Условие2[endif]</div>' + 

                  '</div>' +

                  '<div class="was-here gr-text">' +

                     '<div class="flag"></div>' +

                      ...................................... +

                  '</div>' +

             '</div>'

           );


 


1.Все данные при вёрсте балуна берутся из объекта метки. Например, параметр people_was - это число. Но мне надо не просто вставить это число, а сначала вызвать стороннюю функцию, которая, к примеру, вернёт нам это число с нужным склонением слова(4 - 4 человека, 1 - 1 человек). Можно ли как-то вызывать эту функцию внутри создания класса макета или надо заранее в объект прописать обработанное значение: ...   people_was: someFunction(markerArray.people_was),....? Последний способ очень неудобен, т.к. далее исходное значение(просто цифра) будет использоваться где-то снова. И ещё можно ли в конструкции  [if properties.cost]fee">Условие1[else] использовать условия типа больше меньше или равно и т.д...?


2. Как можно далее менять контент балуна по клику?? Тоесть кликаем на определённую ссылку внутри балуна, затем меняем контент. По факту меняем данные метки, к которой относится балун. И можно ли это делать не перебирая колекцию: кликнули на балун, через него поменяли данные метки ему сопоставленной??

15 комментариев

1. Функцию к полю можно применять при построении макета, но нужно в таком случае переопределять функцию build, в ней вызывать функцию для форматирования и потом вручную устанавливать получившийся html-макет в контент. (примеры переопределения функций у макетов есть в песочнице в разных вариациях).

Условия использовать нельзя, наш язык шаблонов пока что довольно скудный, мы сами мечтаем его улучшить.

2. По клику на балун можно получать ссылку на геообъект через this.getData().geoObject (this - собственно ссылка на макет). У этого геообъекта достаточно перезадать значения полей и балун автоматически перестроится.

Спасибо большое.

var balloonLayout = ymaps.templateLayoutFactory.createClass(

              '' +

                  '' +

                       '' +

                       '' + 

                  '' +

                  '' +

                       '' +

                  '' +

             '',

             {

                  build: function() {

                       balloonLayout.superclass.build.call(this);

                       var objectProperties = this.getData().properties;

             

                       if(objectProperties.get('cost') == 1) $('.color-status').eq(0).addClass('fee').html('контент1');

                       else if(objectProperties.get('cost') == 2) $('.color-status').eq(0).addClass('free').html('контент2');

             

                       if(objectProperties.get('type') == 1) $('.color-status').eq(1).addClass('out').html('контент1');

                       else if(objectProperties.get('type') == 2) $('.color-status').eq(1).addClass('in').html('контент2');

             

                       var peopleCount = objectProperties.get('people_was');

                        if(peopleCount != 0) $('.was-here').append('Здесь ' + (peopleCount == 1 ? 'был' : 'было') + '' + peopleCount + ' ' + getPeopleNumberName(peopleCount) + '');

             

                       if(!objectProperties.get('i_was') || objectProperties.get('i_was') == 0) $('.was-here').append('Я здесь был');

             

                       $('.was-here-link').bind('click', this.makeVisitedMark);

            

                  },

                  clear: function() {

                       $('.was-here-link').unbind('click', this.makeVisitedMark); 

                   },  

                  makeVisitedMark: function() {

                        console.log(this);

                  }

             }

           ); 

Внутри функции  makeVisitedMark я могу как-то обратиться к объекту макета, чтобы изменить свойства у метки??
в this там хранится сама ссылка, на которую щёлкнули. 

можешь
см. jQuery.proxy

 

 

вчера, 17:11

А ещё:

после того как я меняю данные в макете, как поменять содержимое балуна без закрытия-открытия??

Код ниже этого не делает...

var objectProperties = this.getData().properties;

......

success: function(data) {

     if(data.result == "OK") {

      var peopleCount = objectProperties.get('people_was');

      objectProperties.set({people_was: peopleCount + 1}); 

Вроде бы выше  написала что надо так:

this.getData().geoObject.properties,

хотя ты делаешь что-то странное - меняешь данные геообъекта из макета, обычно все наоборот. Данные меняются, - макет перестраивает балун

Переопределяю build, вешаю обработчик на клик по ссылке балуна, отправляю запрос на сервер, если всё ок, то нужно обновить значение у объекта...Такой подход неверен?? - код:

var balloonLayout = ymaps.templateLayoutFactory.createClass(

              '' +

                  '' +

                       '' +

                       '' + 

                  '' +

                  '' +

                       '' +

                  '' +

             '',

             {

             build: function() {

                  balloonLayout.superclass.build.call(this);

                  var objectProperties = this.getData().geoObject.properties;

             

                  if(objectProperties.get('cost') == 1) $('.color-status').eq(0).addClass('fee').html('Платное');

                  else if(objectProperties.get('cost') == 2) $('.color-status').eq(0).addClass('free').html('Бесплатное');

 

                  var peopleCount = objectProperties.get('people_was');

                  if(peopleCount != 0) $('.was-here').append('Здесь ' + (peopleCount == 1 ? 'был' : 'было') + '' + peopleCount + ' ' + getPeopleNumberName(peopleCount) + '');

             

                  if(!objectProperties.get('i_was') || objectProperties.get('i_was') == 0) $('.was-here').append('Я здесь был');

             

                  $('.was-here-link').bind('click', jQuery.proxy(this.makeVisitedMark, this));

            

             },

 

             clear: function() {

                  $('.was-here-link').unbind('click', this.makeVisitedMark);

                  balloonLayout.superclass.clear.call(this);

             },

             

             makeVisitedMark: function() { console.log(1);

                  var objectProperties = this.getData().geoObject.properties;

                  var markerId = objectProperties.get('id');

             

                  var link = $('.ball-content#' + markerId + ' .was-here-link');

                  console.log(link);

                  if(!link.hasClass('enable')) return false;

                  link.removeClass('enable');

                  if(markerId) {

             $.ajax({

                   dataType: 'json',

                   url: mark.php',

                   type: 'POST',

                   data: {

                           markId: markerId

                   },

                   success: function(data) {

                          if(data.result == "OK") {

                          var peopleCount = parseInt(objectProperties.get('people_was'));

                          objectProperties.set({'people_was': peopleCount + 1});

                          //link.replaceWith('Вы здесь были');

   }

   }

             });

   }

   return false;

             }

             }

           ); 

Ну как бы, обновив это значение, вы опять перестроите ваш макет,

т.е. будет вызван clear->build->навешивание клика-> и т.д.

По-хорошему, если рассматривать макет как часть паттерна MVC, а именно View,

то View никогда сам не ходит за данными, это делает модель, т.е. какой-то внешний класс по отношению к View, который затем обновляет данные геообъекта, и View перестраивается.

Если вы посмотрите на те примеры, которыми мы делились в блоге, то там как раз мухи отделены от котлет.

http://ymapsapi.ya.ru/replies.xml?item_no=338

http://ymapsapi.ya.ru/replies.xml?item_no=1034

 

Конечно, Вы можете ходить AJAX-ом и из макета,

только тогда я бы не стал обновлять макет через его перестроение,

а просто вставлял нужные значения в нужные ноды, например так можно сделать,

если вы используете какой-то внешний шаблонизатор вместо примитивного АПИ-шного,

как в последнем примере которым мы поделились вчера в блоге:

http://ymapsapi.ya.ru/replies.xml?item_no=1091

Не совсем понял. Ведь когда мы закрываем балун и снов аоткрывам, всё равно ведь срабатывает  clear->build. Тоесть если я не поменяю само значение в объекте метки, то при следующем открывании там будет старая информация.

Как и где тогда правильно навешивать ajax-запрос на клик?? После создания всех меток пройтись по каждой и повесить на её балун обработчик, который при срабатывании через балун обратится к объекту метки и поменяет там значение??

Суть в том, что имеется набор меток с балунами, все однотипные. при срабатывании клика  нужно отправить данные на сервер, получить результат, изменит содержание балуна(не закрывая/открывая его). При этом и значение самого объекта метки должно измениться, т.к. возможны дальнейшие операции с этой меткой... Можно на примере одного поля объяснить, как это будет?

 

var balloonLayout = ymaps.templateLayoutFactory.createClass(

              '' +

                       '' +

             '

',

             {

             build: function() {

                  balloonLayout.superclass.build.call(this);

                  var objectProperties = this.getData().geoObject.properties;

                  var peopleCount = objectProperties.get('people_was');

                  if(peopleCount != 0) $('.was-here').append('Здесь ' + (peopleCount == 1 ? 'был' : 'было') + '' + peopleCount + ' ' + getPeopleNumberName(peopleCount) + '');

             },

 

             clear: function() {

                  balloonLayout.superclass.clear.call(this);

             }

);

Где бы вы поставили обработчик на клик по балуну, куда ajax, и как правильно задали бы новые значение балуну и объекту(может это в один приём делается)

 

Я бы поместил набор меток в коллекцию и повесил один обработчик на нее (чтобы не вешать обработчик на каждую метку отдельно)

из объекта события, получаем текущий геообъект, на котором кликнули,

через e.get('target'), из его данных получаем id, или что там надо для похода AJAX-ом, идем AJAX-ом на сервер, после получения данных вызываем метод склонения или что там у Вас и затем обновляем данные геообъекта.

Такой способ сильно упростит ваш макет и вынесет всю логику получения данных от их представления в макете

А как повесить обработчик на балуны всех меток коллекции??

С вами кроме как здесь, где-то можно общаться?

можно подписаться на "balloonopen" на коллекции

Лучше наверное здесь, у других пользователей могут возникнуть подобные вопросы

Этот обработчик ведь срабатывает на открытие балуна, а мне нужна определённая ссылка внутри балуна.

И ещё "после получения данных вызываем метод склонения или что там у Вас и затем обновляем данные геообъекта" - проблема в том, что в объекте как раз надо хранить "чистые данные" - они понадобятся для других операций. Нужно, чтобы после смене данных в объекте(после ajax-запроса) запустилась функция(условно та, что работает со склонениями) и "читабельный результат" обновился в контенте балуна.

Про ссылку я не понял о чем речь.

 

Храните и чистые, не вопрос, просто не используйте эти данные в шаблоне.

А функция может все равно быть внешней и результат ее работы так же помещается в properties геообъекта, только уже как раз используется в шаблоне.

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

balloonopen - сработает, когда мы нажмём на метку и откроется балун. А мне нужно событие, которое бы срабатывало при нажатии определённой ссылки внутри балуна каждой метки на карте. После выдернуть id объекта, в чьём балуне была нажата ссылка.

понятно.

Тогда конечно нужно в методе build навешивать обработчик.