Pro jQuery

Pro jQuery

Адам Фриман

Манипулирование шаблонами из функций обработки событий

Вы можете вернуться к шаблону, который был использован для создания элементов и внесения изменений. Вы можете менять шаблон, можете менять данные или опции, которые были использованы для генерации шаблона, или даже для модификации элементов, которые были сгенерированы шаблоном в первый раз. Наиболее распространенной причиной таких действий является потребность в изменении части документа в ответ на действия пользователя, что обозначает, что вы обычно выполняете эти задачи изнутри функции обработки событий, как показано в листинге 12-24.

Листинг 12-24: Изменения шаблона для рендеринга элемента данных
<style type="text/css">
	.bigview
	{
		border: medium solid black;
		position: relative;
		top: -10px;
		left: -10px;
		background-color: white;
	}

		.bigview > img
		{
			width: 160px;
			height: 120px;
		}
</style>

<script type="text/javascript">
	$(document).ready(function () {
		var data = [
			{ name: "Astor", product: "astor", stocklevel: "10", price: "2.99" },
			{ name: "Daffodil", product: "daffodil", stocklevel: "12", price: "1.99" },
			{ name: "Rose", product: "rose", stocklevel: "2", price: "4.99" },
			{ name: "Peony", product: "peony", stocklevel: "0", price: "1.50" },
			{ name: "Primula", product: "primula", stocklevel: "1", price: "3.12" },
			{ name: "Snowdrop", product: "snowdrop", stocklevel: "15", price: "0.99" },
		];
		var templResult = $('#flowerTmpl').tmpl(data);
		templResult.slice(0, 3).appendTo('#row1');
		templResult.slice(3).appendTo("#row2");

		$('div.dcell').mouseenter(handleMouse);

		function handleMouse(e) {
			var tmplItem = $.tmplItem(this);
			var template = e.type == "mouseenter" ? "#flowerTmplSel" : "#flowerTmpl";
			tmplItem.tmpl = $(template).template();
			tmplItem.update();
			$('div.dcell').unbind()
				.bind(e.type == "mouseenter" ? "mouseleave" : "mouseenter", handleMouse);
		}

	});
</script>
<script id="flowerTmpl" type="text/x-jquery-tmpl">
	<div class="dcell">
		<img src="${product}.png" />
		<label for="${product}">${name}: </label>
		<input name="${product}" value="0" required />
	</div>
</script>
<script id="flowerTmplSel" type="text/x-jquery-tmpl">
	<div class="dcell bigview">
		<img src="${product}.png" />
		{{if $data.stocklevel > 0}}
			Stock: ${stocklevel} Price: $${price}
		{{else}}
			(Out of stock)
		{{/if}}
	</div>
</script>

Этот пример требует тщательного пояснения. Тут вас могут поджидать некоторые сюрпризы и проблемы, которые могут возникнуть по неосторожности. Основная идея этого примера довольно проста. У вас есть объект внутренних данных, который воспроизводится при помощи шаблона flowerTmpl.

После воспроизведения содержания я использую метод mouseenter, чтобы зарегистрировать функцию handleMouseв качестве обработчика для элементов, которые подходят элементам div.dcell. Это элементы самого высокого уровня, которые воспроизвел шаблон.

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

var tmplItem = $.tmplItem(this);

Это тот же вид объекта, который вы можете получить, используя переменную $item внутри шаблона (как было описано ранее в этой главе), но тут объект намного более полезный. В таблице 12-3 показаны свойства этого объекта шаблона.

Таблица 12-3: Свойства объекта элемента шаблона
Имя Описание
nodes Набор элементов HTMLElement, которые были сгенерированы шаблоном. Иерархия объектов сохраняется, поэтому этим свойством возвращаются только элементы самого высокого уровня
data Объект данный, используемый для воспроизведения элемента
tmpl Шаблон, используемый для генерирования выбранного элемента
parent Родительский шаблон, если элемент был сгенерирован из вложенного шаблона
<option properties> Свойства, определенные объектом options (если использовался) доступны напрямую в этом объекте

Возвращаясь к примеру, я выбираю шаблон, который я хочу использовать для отображения выбранного элемента, основываясь на типы события. Если мышка входит в область элемента, я выбираю шаблон flowerTmplSel:

var template = e.type == "mouseenter" ? "#flowerTmplSel" : "#flowerTmpl";

Затем я использую свойство элемента шаблона tmpl, чтобы связать шаблон с элементом данных:

tmplItem.tmpl = $(template).template();

В размышлениях о том, что здесь происходит, нам поможет понимание того, что движок шаблона запоминает, как он генерировал содержание, которые вы сейчас пытаетесь изменить. Он сохраняет запись об объекте данных и шаблоне, который вы использовали. Это ловкий трюк, и он работает даже тогда, когда вы используете условие и вложенные шаблоны. Используя свойство tmpl, я говорю движку шаблона, что я хочу использовать другой шаблон, чтобы сгенерировать содержание элемента данных, который первоначально был использован для генерирования элемента, который запустил событие, которое мы сейчас обрабатываем (возможно, вам потребуется прочитать это предложение пару раз, чтобы точно понять его).

Когда вы закончили делать изменения, вы вызываете метод update для элемента шаблона, чтобы заново воспроизвести содержание, используя новые значения (в данном случае новый шаблон):

tmplItem.update();

Как применяется новый шаблон, можно увидеть на рисунке 12-10.

Рисунок 12-10: Использование другого шаблона, когда мышка находится над элементом

Последнее выражение в функции handleMouse следующее:

$('div.dcell').unbind().bind(e.type == "mouseenter" ? "mouseleave" : "mouseenter", handleMouse);

Когда вы меняете шаблон, сгенерированные до этого элементы удаляются из документа и заменяются другими, сгенерированными новым шаблоном. Это обозначает, что любой обработчик событий также удаляется. Это последствия довольно печального взаимодействия между библиотекой шаблонов и основной библиотекой jQuery, что обозначает, что метод live (описанный в главе 9) не работает корректно, и вам нужно быть очень аккуратными, когда вы возвращаете нужные вам обработчики.

Изменение данных, используемых шаблоном

Можно менять данные, используемые шаблоном, и заставлять движок шаблона заново генерировать элементы, используя новые значения. В листинге 12-25 есть пример.

Листинг 12-25: Изменение данных, используемых шаблоном
<script type="text/javascript">
	$(document).ready(function () {
		var data = [
			{ name: "Astor", product: "astor", stocklevel: "10", price: "2.99" },
			{ name: "Daffodil", product: "daffodil", stocklevel: "12", price: "1.99" },
			{ name: "Rose", product: "rose", stocklevel: "2", price: "4.99" },
			{ name: "Peony", product: "peony", stocklevel: "0", price: "1.50" },
			{ name: "Primula", product: "primula", stocklevel: "1", price: "3.12" },
			{ name: "Snowdrop", product: "snowdrop", stocklevel: "15", price: "0.99" },
		];

		var templResult = $('#flowerTmpl').tmpl(data);
		templResult.slice(0, 3).appendTo('#row1');
		templResult.slice(3).appendTo("#row2");

		$('<button>Modify Data</button>').prependTo("#buttonDiv").click(function (e) {
			var item = $.tmplItem($('div.dcell').first());
			item.data.product = "orchid";
			item.data.name = "Orchid";
			item.update();
			e.preventDefault();
		});
	});
</script>
<script id="flowerTmpl" type="text/x-jquery-tmpl">
	<div class="dcell">
		<img src="${product}.png" />
		<label for="${product}">${name}: </label>
		<input name="${product}" value="0" required />
	</div>
</script>

В этом примере я добавляю в документ button. Когда кнопка нажимается, я получаю элемент шаблона для элемента, который подходит селектору div.dcell, и использую свойство data, чтобы сделать изменения в объектах данных:

var item = $.tmplItem($('div.dcell').first());
item.data.product = "orchid";
item.data.name = "Orchid";

Затем я вызываю метод update, чтобы заново сгенерировать содержание, используя новые значения. Результат можно увидеть на рисунке 12-11.

Рисунок 12-11: Изменение данных, связанных с шаблоном

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

Листинг 12-26: Изменение значений объекта данных напрямую
<script type="text/javascript">
	$(document).ready(function () {
		var data = [
			{ name: "Astor", product: "astor", stocklevel: "10", price: "2.99" },
			{ name: "Daffodil", product: "daffodil", stocklevel: "12", price: "1.99" },
			{ name: "Rose", product: "rose", stocklevel: "2", price: "4.99" },
			{ name: "Peony", product: "peony", stocklevel: "0", price: "1.50" },
			{ name: "Primula", product: "primula", stocklevel: "1", price: "3.12" },
			{ name: "Snowdrop", product: "snowdrop", stocklevel: "15", price: "0.99" },
		];
		var templResult = $('#flowerTmpl').tmpl(data);
		templResult.slice(0, 3).appendTo('#row1');
		templResult.slice(3).appendTo("#row2");;
		data[0].name = "Orchid";
		data[0].product = "orchid";
		$('<button>Modify Data</button>').prependTo("#buttonDiv").click(function (e) {
			var item = $.tmplItem($('div.dcell').first()).update();
			e.preventDefault();
		});
	});
</script>
или RSS канал: Что новенького на smarly.net