#javascript #jquery #jquery-data
#javascript #jquery #jquery-данные
Вопрос:
Я пишу плагин jQuery, и мне нужно сохранять объекты с помощью вызовов метода моего плагина. Поэтому я попытался использовать, .data()
как рекомендовано здесь : http://docs.jquery.com/Plugins/Authoring
но я не могу получить свои сохраненные объекты, вот мой код :
(function($) {
var methods = {
init : function(options) {
return this.each(function() {
var $this = $(this);
var geocoder = new google.maps.Geocoder();
var settings = {
'geocodeSearch': {address: 'France'}
};
// Merge default settings with user ones
if (options) {
$.extend(settings, options);
}
function drawMap(geocodeResult) {
var mapSettings = {
center: geocodeResult[0].geometry.location,
mapTypeControl: true,
mapTypeId: google.maps.MapTypeId.SATELLITE,
overviewMapControl: false,
panControl: true,
scaleControl: true,
streetViewControl: false,
zoom: 6,
zoomControl: true,
zoomControlOptions: { style: google.maps.ZoomControlStyle.SMALL }
};
var element = document.getElementById($this.attr("id"));
var map = new google.maps.Map(element, mapSettings);
var cluster = new MarkerClusterer(map);
cluster.setGridSize(100);
$this.data('eventsmap', {
cluster: cluster,
map: map
});
}
geocoder.geocode(settings.geocodeSearch, drawMap);
});
},
restrictZoom : function(minimalZoom, maximalZoom) {
return this.each(function() {
var $this = $(this);
console.log($this.data());
console.log($this.data('eventsmap'));
//google.maps.event.addListener(map, 'zoom_changed', function() {
// if (map.getZoom() > maximalZoom) {
// map.setZoom(maximalZoom);
// }
// if (map.getZoom() < minimalZoom) {
// map.setZoom(minimalZoom);
// }
//});
//cluster.setMaxZoom(maximalZoom-1);
});
}
};
$.fn.eventsMap = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error( 'Method ' method ' does not exist on jQuery.eventsMap' );
}
};
})(jQuery);
Когда я вызываю метод Restrict Zoom, $this.data() (строка 48) возвращает данные из DOM, но если я попытаюсь получить атрибут ‘eventsmap’, установленный во время метода init, я получу undefined ($this.data(‘eventsmap’) строка 49).
Я уверен, что это правильный объект DOM, и мои объекты есть, потому что я могу видеть их через отладчик моего браузера :
Я не знаю, что делать.
Отредактировано: html :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us" xml:lang="en-us" >
<head>
<title>Map tool | Django site admin</title>
<link rel="stylesheet" type="text/css" href="/static/admin/css/base.css" />
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/ui-darkness/jquery-ui.css" />
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="/static/admin/css/ie.css" /><![endif]-->
<script type="text/javascript">window.__admin_media_prefix__ = "/static/admin/";</script>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.js"></script>
<script type="text/javascript" src="/static/earthquake/js/markerclusterer.js"></script>
<script type="text/javascript" src="/static/earthquake/js/map.js"></script>
<meta name="robots" content="NONE,NOARCHIVE" />
</head>
<body class="eventsmap">
<!-- Container -->
<div id="container">
<!-- Header -->
<div id="header">
<div id="branding">
<h1 id="site-name">Events database</h1>
</div>
<div id="user-tools">
Welcome,
<strong>admin</strong>.
<a href="/admin/doc/">Documentation</a> /
<a href="/admin/password_change/">
Change password</a> /
<a href="/admin/logout/">
Log out</a>
</div>
</div>
<!-- END Header -->
<div class="breadcrumbs">
<a href="/admin/">Home</a> amp;rsaquo; <a href="/admin/events">Events</a> amp;rsaquo; Map tool
</div>
<!-- Content -->
<div id="content" class="colM">
<div id="eventsmap" style="width: 100%;"></div>
<script>
$(document).ready(function() {
var mapCanvas = $("#eventsmap");
// Cleanup and prepare HTML from Django
$("#footer").remove();
$("html").height("100%");
$("body").height("100%");
$("body").css("overflow-y", "hidden");
$("#content").css('margin', 0);
mapCanvas.height($(document).height()-57);
mapCanvas.eventsMap({
geocodeSearch: {address: 'France'}
});
mapCanvas.eventsMap('restrictZoom', {
minimalZoom: 2,
maximalZoom: 9
});
});
</script>
<br class="clear" />
</div>
<!-- END Content -->
<div id="footer"></div>
</div>
<!-- END Container -->
</body>
</html>
Комментарии:
1.
console.log($this)
при настройке / получении данных, чтобы увидеть, действительно ли вы обращаетесь к тем же объектам…2. У меня ничего не выскакивает. Возможно, если бы вы включили код того, как это вызывается.
3. инициализация и restrictZoom используются для одного и того же объекта, и я использую этот плагин только для одного объекта моей страницы. Итак, я думаю, что это одно и то же между init и Restrict Zoom, потому что я добавляю ‘eventsmap’ dict в init и увидел это в методе Restrict Zoom (но я новичок в Js). И я только что увидел эту ошибку, открытую несколько часов назад в jQuery bugtracker : bugs.jquery.com/ticket/8986 Итак, я попробовал с предыдущей версией (1.5.1), но у меня все еще та же проблема :/
4. Я только что попытался добавить console.log ($ this) в init и Restrict Zoom, там один и тот же объект.
5. Добавлен HTML, чтобы показать, как он вызывается.
Ответ №1:
В целом код выглядит действительно хорошо. Но вот две идеи:
-
Пытались ли вы сохранить более простой объектный литерал в этой функции данных, чтобы убедиться, что код работает иначе? В данный момент вы сохраняете объект Google Map и MarkerCluster. Являются ли эти объекты слишком сложными для кодирования в json и хранения в атрибуте данных? (Не могу вспомнить, являются ли они просто объектными литералами или в них также есть функции и другие элементы)
-
Просто стилистическая особенность, но есть ряд повторно используемых имен, которые затрудняют отладку кода. (в целом ваш код великолепен) Есть две разные переменные с именем $this (в разных областях это выглядит так) и три элемента с именем eventsmap (класс css, переменная js и функция расширения). Хотя они, вероятно, в порядке, это может сбить с толку некоторых людей, читающих этот код.
Я надеюсь, что это породит несколько идей!
Комментарии:
1. вы можете хранить замыкания как значения в карте данных, поэтому сохранение этих двух вещей не должно быть проблемой
Ответ №2:
Я, наконец, понял, почему это не сработало, я должен был убедиться, что методы плагина вызываются синхронно. Чтобы реализовать это, я оборачиваю свои методы в функцию jQuery .queue следующим образом :
(function($) {
var methods = {
init : function(options) {
return this.each(function() {
$(this).queue(function() {
var $this = $(this), data = $this.data('eventsmap');
var geocoder = new google.maps.Geocoder();
var settings = {
'geocodeSearch': {address: 'France'}
};
// Merge default settings with user ones
if (options) {
$.extend(settings, options);
}
function drawMap(geocodeResult) {
var mapSettings = {
center: geocodeResult[0].geometry.location,
mapTypeControl: true,
mapTypeId: google.maps.MapTypeId.SATELLITE,
overviewMapControl: false,
panControl: true,
scaleControl: true,
streetViewControl: false,
zoom: 6,
zoomControl: true,
zoomControlOptions: { style: google.maps.ZoomControlStyle.SMALL }
};
var element = document.getElementById($this.attr("id"));
var map = new google.maps.Map(element, mapSettings);
var cluster = new MarkerClusterer(map);
cluster.setGridSize(100);
if (!data) {
$this.data('eventsmap', {
cluster: cluster,
map: map
});
}
$this.dequeue();
}
geocoder.geocode(settings.geocodeSearch, drawMap);
})
});
},
restrictZoom : function(args) {
var minimalZoom = args.minimalZoom;
var maximalZoom = args.maximalZoom;
return this.each(function() {
$(this).queue(function() {
var $this = $(this), data = $this.data('eventsmap');
google.maps.event.addListener(data.map, 'zoom_changed', function() {
if (data.map.getZoom() > maximalZoom) {
data.map.setZoom(maximalZoom);
}
if (data.map.getZoom() < minimalZoom) {
data.map.setZoom(minimalZoom);
}
});
data.cluster.setMaxZoom(args.maximalZoom-1);
$(this).dequeue();
});
});
}
};
$.fn.eventsMap = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error( 'Method ' method ' does not exist on jQuery.eventsMap' );
}
};
})(jQuery);
Теперь это работает как по волшебству, я вызывал MyObject.data (‘eventsmap’) до того, как он был установлен в методе init кстати, я все еще не могу объяснить, почему я мог видеть объект в браузере … 🙂