<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Miximum &#187; javascript</title>
	<atom:link href="http://www.miximum.fr/tag/javascript/feed" rel="self" type="application/rss+xml" />
	<link>http://www.miximum.fr</link>
	<description>Le blog d&#039;un ingénieur web freelance</description>
	<lastBuildDate>Wed, 16 Nov 2011 16:25:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Autocomplete avec Solr</title>
		<link>http://www.miximum.fr/methodes-et-outils/499-autocomplete-avec-solr</link>
		<comments>http://www.miximum.fr/methodes-et-outils/499-autocomplete-avec-solr#comments</comments>
		<pubDate>Mon, 27 Sep 2010 13:22:17 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Méthodes et outils]]></category>
		<category><![CDATA[autocomplete]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[solr]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=499</guid>
		<description><![CDATA[photo credit&#160;: Thibault Jouannic Voil&#224; la reprise, les premiers froids, les feuilles qui tombent, la nostalgie des vacances, etc. Mais la rentr&#233;e est &#233;galement pour moi l&#8217;opportunit&#233; de d&#233;poussi&#233;rer un peu mon cerveau et ce blog, avec du temps consacr&#233; &#224; l&#8217;indispensable&#8230; Veille techno. Parce que la veille, c&#8217;est comme le sport. Quand on ne [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignright"><a href="http://www.flickr.com/photos/24469297@N05/5005748830/" title="Purple sunset in Ko Tao" target="_blank"><img src="http://farm5.static.flickr.com/4113/5005748830_ccfd81aa54_m.jpg" alt="Purple sunset in Ko Tao" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-nd/2.0/" title="Attribution-NonCommercial-NoDerivs License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/24469297@N05/" title="Thibault Jouannic Photo" target="_blank">Thibault Jouannic</a></small></div>
<p>Voil&agrave; la reprise, les premiers froids, les feuilles qui tombent, la nostalgie des vacances, etc. Mais la rentr&eacute;e est &eacute;galement pour moi l&#8217;opportunit&eacute; de d&eacute;poussi&eacute;rer un peu mon cerveau et ce blog, avec du temps consacr&eacute; &agrave; l&#8217;indispensable&hellip; Veille techno. Parce que la veille, c&#8217;est comme le sport. Quand on ne pratique pas, on s&#8217;encrasse vite. <a href="http://thibault.jouannic.fr" title="D&eacute;veloppeur web freelance">Surtout quand on est freelance</a>.</p>
<p>Bref, dans cet article, nous allons utiliser <a href="http://www.miximum.fr/tag/solr" title="Solr, search engine">Solr, excellent moteur de recherche</a> dont je vous ai d&eacute;j&agrave; parl&eacute;, et impl&eacute;menter <strong>l&#8217;autocompl&eacute;tion de la recherche</strong>.</p>
<h2>Solr pour l&#8217;autocompl&eacute;tion, ou sortir la Grosse Bertha pour tuer une mite</h2>
<p>Les plus attentifs d&#8217;entre vous se demanderont sans doute pourquoi utiliser Solr, puissant moteur de recherche full-text en java, pour une b&ecirc;te autocompl&eacute;tion. Et effectivement, l&#8217;outil serait disproportionn&eacute; si nous n&#8217;&eacute;tions pas dans un des cas suivants&nbsp;:</p>
<ol>
<li>Vous utilisez d&eacute;j&agrave; Solr pour votre moteur de recherche. Dans ce cas, l&#8217;utiliser pour l&#8217;autocompl&eacute;tion ne rajoutera pas une grosse charge&nbsp;<span class="fine">&nbsp;</span>;</li>
<li>Vous souhaitez mettre en place une autocompl&eacute;tion un peu avanc&eacute;e, avec s&eacute;paration par facettes, etc&nbsp;<span class="fine">&nbsp;</span>;</li>
</ol>
<p>Solr, depuis la version 1.4, propose un <a href="http://wiki.apache.org/solr/TermsComponent">nouveau module de recherche&nbsp;: Terms Component</a>. Alors que Solr est g&eacute;n&eacute;ralement utilis&eacute; pour effectuer des recherches au niveau d&#8217;un document, ce module permet d&#8217;acc&eacute;der au infos au niveau des termes pr&eacute;sents dans les champs, permettant de r&eacute;pondre &agrave; la requ&ecirc;te&nbsp;: &laquo;&nbsp;Quels sont les termes pr&eacute;sent dans tel(s) champ(s), et &agrave; combien de document correspondent-ils<span class="fine">&nbsp;</span>?&nbsp;&raquo;.</p>
<p>Par ailleurs, notez que nous allons cr&eacute;er une autocompl&eacute;tion, et pas une autosuggestion. Pour bien cerner la diff&eacute;rence, je vous recommande la lecture de cet <a href="http://blog.twigkit.com/search-suggestions-part-1/">excellent article sur les diff&eacute;rents types d&#8217;assistance &agrave; la recherche</a>.</p>
<div class="postimg alignleft"><a href="http://www.flickr.com/photos/24469297@N05/5029647182/" title="autocomplete by teeboo2734, on Flickr"><img src="http://farm5.static.flickr.com/4110/5029647182_b6d21d67f0_m.jpg" width="196" height="240" alt="autocomplete" /></a></div>
<p>Pour &ecirc;tre pr&eacute;cis, nous allons construire &ccedil;a. Ceux qui lisent via un lecteur rss et qui n&#8217;auraient pas l&#8217;image, vous n&#8217;avez qu&#8217;&agrave; aller sur le site.</p>
<p>Pour les autres, vous remarquerez un b&ecirc;te champ de recherche tout ce qu&#8217;il y a de plus classique. L&#8217;autocompl&eacute;tion, en revanche, est un tantinet &eacute;volu&eacute;e, puisqu&#8217;elle s&#8217;effectue sur deux champs diff&eacute;rents. Vous &ecirc;tes pr&ecirc;ts<span class="fine">&nbsp;</span>? C&#8217;est parti<span class="fine">&nbsp;</span>!</p>
<h2>Choisir les bons outils</h2>
<p>&Agrave; l&#8217;heure ou j&#8217;&eacute;cris, la version stable de Solr est la 1.4.1. Elle pr&eacute;sente toutefois un bug dans le formatage json des r&eacute;sultats. Nous utiliserons donc Solr dans sa version nightly build.</p>
<p>L&#8217;autocomplete sera assur&eacute; par <a href="http://jquery.com/">jQuery, librairie javascript que l&#8217;on ne pr&eacute;sente plus</a>, et par son tr&eacute;s bon compl&eacute;ment <a href="http://jqueryui.com/demos/autocomplete/">jQuery UI</a>.</p>
<p>Notez l&#8217;existance d&#8217;une tr&eacute;s compl&egrave;te (mais assez complexe) <a href="http://github.com/evolvingweb/ajax-solr">librairie ajax pour Solr</a>. Elle constitue pratiquement un framework &agrave; elle toute seule, et pour le coup, nous la laisserons de c&ocirc;t&eacute;.</p>
<h2>Le code<span class="fine">&nbsp;</span>! Le code<span class="fine">&nbsp;</span>!</h2>
<p>Commen&ccedil;ons par le HTML. Ici, rien que du classique.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc0">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span class="sc3"><span class="re1">&lt;html</span> <span class="re0">xmlns</span>=<span class="st0">&quot;http://www.w3.org/1999/xhtml&quot;</span> <span class="re0">xml:lang</span>=<span class="st0">&quot;fr&quot;</span><span class="re2">&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;./js/jquery-1.4.2.min.js&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;./js/jquery-ui-1.8.5.custom.min.js&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;./js/solr.js&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
&nbsp;
    <span class="sc3"><span class="re1">&lt;link</span> <span class="re0">rel</span>=<span class="st0">&quot;stylesheet&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;text/css&quot;</span> <span class="re0">media</span>=<span class="st0">&quot;screen&quot;</span> <span class="re0">href</span>=<span class="st0">&quot;./css/ui-lightness/jquery-ui-1.8.5.custom.css&quot;</span> <span class="re2">/&gt;</span></span>
&nbsp;
  <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;form</span> <span class="re0">action</span>=<span class="st0">&quot;&quot;</span> <span class="re0">method</span>=<span class="st0">&quot;get&quot;</span><span class="re2">&gt;</span></span>
      <span class="sc3"><span class="re1">&lt;input</span> <span class="re0">type</span>=<span class="st0">&quot;text&quot;</span> <span class="re0">id</span>=<span class="st0">&quot;search&quot;</span> <span class="re0">name</span>=<span class="st0">&quot;q&quot;</span> <span class="re2">/&gt;</span></span>
      <span class="sc3"><span class="re1">&lt;input</span> <span class="re0">type</span>=<span class="st0">&quot;submit&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;Search&quot;</span> <span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;/form<span class="re2">&gt;</span></span></span>
&nbsp;
    <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;result&quot;</span><span class="re2">&gt;</span></span>
      <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Results go here<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Un banal champ texte, l&#8217;inclusion des scripts n&eacute;cessaires, et c&#8217;est tout. Circulez, ya rien &agrave; voir<span class="fine">&nbsp;</span>!</p>
<p>La configuration Solr n&#8217;est pas tr&eacute;s int&eacute;ressante non plus. J&#8217;ai pris la premi&egrave;re install de Solr qui m&#8217;est pass&eacute;e sous la main. Vous pouvez vous r&eacute;ferer au schema.xml d&#8217;un pr&eacute;c&eacute;dent article.</p>
<p>Le seul fichier vraiment int&eacute;ressant est le javascript&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$<span class="br0">&#40;</span>document<span class="br0">&#41;</span>.<span class="me1">ready</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  $<span class="br0">&#40;</span><span class="st0">'#search'</span><span class="br0">&#41;</span>.<span class="me1">autocomplete</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
    source<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>request<span class="sy0">,</span> response<span class="br0">&#41;</span> <span class="br0">&#123;</span>
      $.<span class="me1">ajax</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
        url<span class="sy0">:</span> <span class="st0">'http://localhost:8983/solr/terms?terms.fl=name'</span><span class="sy0">,</span>
        dataType<span class="sy0">:</span> <span class="st0">'jsonp'</span><span class="sy0">,</span>
        data<span class="sy0">:</span> <span class="br0">&#123;</span>
          wt<span class="sy0">:</span> <span class="st0">'json'</span><span class="sy0">,</span>
          <span class="st0">'json.nl'</span><span class="sy0">:</span> <span class="st0">'arrarr'</span><span class="sy0">,</span>
          <span class="st0">'terms.prefix'</span><span class="sy0">:</span> request.<span class="me1">term</span><span class="sy0">,</span>
          <span class="st0">'terms.sort'</span><span class="sy0">:</span> <span class="st0">'index'</span><span class="sy0">,</span>
          <span class="st0">'terms.limit'</span><span class="sy0">:</span> <span class="nu0">5</span><span class="sy0">,</span>
          omitHeader<span class="sy0">:</span> <span class="st0">'true'</span>
        <span class="br0">&#125;</span><span class="sy0">,</span>
        jsonp<span class="sy0">:</span> <span class="st0">'json.wrf'</span><span class="sy0">,</span>
        success<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span> <span class="br0">&#123;</span>
          response<span class="br0">&#40;</span>$.<span class="me1">map</span><span class="br0">&#40;</span>data.<span class="me1">terms</span>.<span class="kw3">name</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="kw1">item</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
            <span class="kw1">return</span> <span class="br0">&#123;</span>
              label<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">' ('</span> <span class="sy0">+</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">')'</span><span class="sy0">,</span>
              value<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>
            <span class="br0">&#125;</span><span class="sy0">;</span>
          <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>Quelques explications. Dans l&#8217;url utilis&eacute;e par le widget d&#8217;autocompl&eacute;tion, <em>terms.fl</em> d&eacute;signe le champ qui sera utilis&eacute; pour la requ&ecirc;te (ici&nbsp;: &laquo;&nbsp;name&nbsp;&raquo;).</p>
<p>Notez les options &laquo;&nbsp;datatype&nbsp;: jsonp&nbsp;&raquo;, &laquo;&nbsp;wt&nbsp;: json&nbsp;&raquo;, &laquo;&nbsp;json.nl&nbsp;: arrarr&nbsp;&raquo;, &laquo;&nbsp;jsonp&nbsp;: wrf&nbsp;&raquo;. Elles permettent de faire fonctionner l&#8217;appel ajax en cross-domain (via jsonp au lieur de json), et d&#8217;obtenir un formatage correct du r&eacute;sultat de la part de Solr.</p>
<p>Enfin, dans le callback &laquo;&nbsp;result&nbsp;&raquo;, nous formattons le r&eacute;sultat en utilisant la <a href="http://api.jquery.com/jQuery.map"/>fonction $.map de jquery</a>.</p>
<p>Nous avons maintenant un widget de recherche qui r&eacute;alise une autocompl&eacute;tion sur le champ &laquo;&nbsp;name&nbsp;&raquo;. C&#8217;est pas mal, mais nous souhaitions une autocompl&eacute;tion &agrave; facette sur diff&eacute;rents champs.</p>
<h2>L&#8217;autocompl&eacute;tion &agrave; facette</h2>
<p>Pour ce faire, nous allons modifier deux choses. D&#8217;abord, il va falloir d&eacute;finir un template de widget sp&eacute;cifique pour afficher le champ recherch&eacute;. Ensuite, la fonction qui parse le r&eacute;sultat renvoy&eacute; par Solr va devoir prendre en compte les diff&eacute;rents champs.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$<span class="br0">&#40;</span>document<span class="br0">&#41;</span>.<span class="me1">ready</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
  <span class="co1">// Widget autocomplete spécifique</span>
  <span class="co1">// cf. http://jqueryui.com/demos/autocomplete/#categories</span>
  $.<span class="me1">widget</span><span class="br0">&#40;</span> <span class="st0">&quot;custom.catcomplete&quot;</span><span class="sy0">,</span> $.<span class="me1">ui</span>.<span class="me1">autocomplete</span><span class="sy0">,</span> <span class="br0">&#123;</span>
    _renderMenu<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span> ul<span class="sy0">,</span> items <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw2">var</span> self <span class="sy0">=</span> <span class="kw1">this</span><span class="sy0">,</span>
        currentCategory <span class="sy0">=</span> <span class="st0">&quot;&quot;</span><span class="sy0">;</span>
      $.<span class="me1">each</span><span class="br0">&#40;</span> items<span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span> index<span class="sy0">,</span> <span class="kw1">item</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw1">item</span>.<span class="me1">category</span> <span class="sy0">!=</span> currentCategory <span class="br0">&#41;</span> <span class="br0">&#123;</span>
          ul.<span class="me1">append</span><span class="br0">&#40;</span> <span class="st0">&quot;&lt;li class='ui-autocomplete-category'&gt;&quot;</span> <span class="sy0">+</span> <span class="kw1">item</span>.<span class="me1">category</span> <span class="sy0">+</span> <span class="st0">&quot;&lt;/li&gt;&quot;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
          currentCategory <span class="sy0">=</span> <span class="kw1">item</span>.<span class="me1">category</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
        self._renderItem<span class="br0">&#40;</span> ul<span class="sy0">,</span> <span class="kw1">item</span> <span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  $<span class="br0">&#40;</span><span class="st0">'#search'</span><span class="br0">&#41;</span>.<span class="me1">catcomplete</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
    source<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>request<span class="sy0">,</span> response<span class="br0">&#41;</span> <span class="br0">&#123;</span>
      $.<span class="me1">ajax</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
        url<span class="sy0">:</span> <span class="st0">'http://localhost:8983/solr/terms?terms.fl=name&amp;terms.fl=tag_fr'</span><span class="sy0">,</span>
        dataType<span class="sy0">:</span> <span class="st0">'jsonp'</span><span class="sy0">,</span>
        data<span class="sy0">:</span> <span class="br0">&#123;</span>
          wt<span class="sy0">:</span> <span class="st0">'json'</span><span class="sy0">,</span>
          <span class="st0">'json.nl'</span><span class="sy0">:</span> <span class="st0">'arrarr'</span><span class="sy0">,</span>
          <span class="st0">'terms.prefix'</span><span class="sy0">:</span> request.<span class="me1">term</span><span class="sy0">,</span>
          <span class="st0">'terms.sort'</span><span class="sy0">:</span> <span class="st0">'index'</span><span class="sy0">,</span>
          <span class="st0">'terms.limit'</span><span class="sy0">:</span> <span class="nu0">5</span><span class="sy0">,</span>
          omitHeader<span class="sy0">:</span> <span class="st0">'true'</span>
        <span class="br0">&#125;</span><span class="sy0">,</span>
        jsonp<span class="sy0">:</span> <span class="st0">'json.wrf'</span><span class="sy0">,</span>
        success<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
          answer <span class="sy0">=</span> <span class="kw2">new</span> Array<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
          $.<span class="me1">each</span><span class="br0">&#40;</span>data.<span class="me1">terms</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span>facet<span class="sy0">,</span> terms<span class="br0">&#41;</span> <span class="br0">&#123;</span>
            answer <span class="sy0">=</span> answer.<span class="me1">concat</span><span class="br0">&#40;</span>$.<span class="me1">map</span><span class="br0">&#40;</span>terms<span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="kw1">item</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
              <span class="kw1">return</span> <span class="br0">&#123;</span>
                label<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">' ('</span> <span class="sy0">+</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">')'</span><span class="sy0">,</span>
                value<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="sy0">,</span>
                category<span class="sy0">:</span> facet
              <span class="br0">&#125;</span><span class="sy0">;</span>
            <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
          <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
          response<span class="br0">&#40;</span>answer<span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>Notez l&#8217;url utilis&eacute;e dans le widget autocomplete&nbsp;: il y a maintenant deux options &laquo;&nbsp;terms.fl&nbsp;&raquo;, mais il pourrait y en avoir beaucoup plus.</p>
<p>La fonction d&#8217;analyse des r&eacute;sultats est un peu plus complexe. Pour chaque champ renvoy&eacute; par solr, elle construit un tableau de termes, en y adjoignant la cat&eacute;gorie, c&#8217;est &agrave; dire le champ courant. Tous les tableaux sont ensuite concat&eacute;n&eacute;s, en renvoy&eacute;s en r&eacute;ponse.</p>
<p>La cat&eacute;gorie est utilis&eacute;e par le template de rendu du widget, pour &ecirc;tre affich&eacute;e dans le menu d&#8217;autocompl&eacute;tion.</p>
<p>Dans nos styles, il faudra ajouter ceci&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="re1">.ui-autocomplete-category</span> <span class="br0">&#123;</span>
  <span class="kw1">font-weight</span><span class="sy0">:</span> <span class="kw2">bold</span><span class="sy0">;</span>
  <span class="kw1">padding</span><span class="sy0">:</span> <span class="re3">.2em</span> <span class="re3">.4em</span><span class="sy0">;</span>
  <span class="kw1">margin</span><span class="sy0">:</span> <span class="re3">.8em</span> <span class="nu0">0</span> <span class="re3">.2em</span><span class="sy0">;</span>
  <span class="kw1">line-height</span><span class="sy0">:</span> <span class="nu0">1.5</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Et voil&agrave;<span class="fine">&nbsp;</span>! Un widget d&#8217;autocompl&eacute;tion un poil moins que basique. Partant de cette base, je vous laisse imaginer les am&eacute;liorations les plus raffin&eacute;es. Si vous avez des id&eacute;es de d&eacute;mo, je suis preneur.</p>
<p>&#8211; Edit &#8211;</p>
<p>J&#8217;ai oubli&eacute; de mentionner le probl&egrave;me de la s&eacute;curit&eacute;. Bien entendu, c&#8217;est une tr&eacute;s mauvaise id&eacute;e de laisser Solr en acc&egrave;s libre depuis l&#8217;ext&eacute;rieur. Donc ou bien vous cr&eacute;ez un proxy, ou bien vous cr&eacute;ez un <em>requesthandler</em> sp&eacute;cifique en lecture seule. C&#8217;est tout.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/methodes-et-outils/499-autocomplete-avec-solr/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Créer une liste triable avec Symfony et jquery ui</title>
		<link>http://www.miximum.fr/tutos/435-creer-une-liste-triable-avec-symfony-et-jquery-ui</link>
		<comments>http://www.miximum.fr/tutos/435-creer-une-liste-triable-avec-symfony-et-jquery-ui#comments</comments>
		<pubDate>Sat, 23 Jan 2010 12:23:57 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Tutos]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=435</guid>
		<description><![CDATA[Lors de mes d&#233;veloppements de ces derniers jours, je suis tomb&#233; sur un besoin qui me semblait relativement simple. Je voulais &#234;tre capable de trier rapidement une liste d&#8217;&#233;l&#233;ments. Et comme, malgr&#233; tout, j&#8217;ai un peu gal&#233;r&#233; &#224; trouver des tutoriaux &#224; jour, je vous livre ici le fruit de mes travaux. J&#8217;utiliserai pour ce [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignleft"><a href="http://www.flickr.com/photos/24469297@N05/4297558881/" title="Symfony backlog" target="_blank"><img src="http://farm5.static.flickr.com/4068/4297558881_f8b9f64056_m.jpg" alt="Symfony backlog" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-sa/2.0/" title="Attribution-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> </small></div>
<p>Lors de mes d&eacute;veloppements de ces derniers jours, je suis tomb&eacute; sur un besoin qui me semblait relativement simple. Je voulais &ecirc;tre capable de trier rapidement une liste d&#8217;&eacute;l&eacute;ments. Et comme, malgr&eacute; tout, j&#8217;ai un peu gal&eacute;r&eacute; &agrave; trouver des tutoriaux &agrave; jour, je vous livre ici le fruit de mes travaux.</p>
<p>J&#8217;utiliserai pour ce faire la <a href="http://jqueryui.com/">librairie jquery UI</a>, elle m&ecirc;me bas&eacute;e sur Jquery.</p>
<p>Attention, hein, c&#8217;est samedi matin, je suis mal r&eacute;veill&eacute;, &minus; edit&nbsp;: tellement mal r&eacute;veill&eacute; que j&#8217;ai publi&eacute; l&#8217;article avant de l&#8217;avoir termin&eacute;. fail&hellip; &minus; alors je raccourcirai au maximum. Si je ne suis pas clair, laissez moi des commentaires.</p>
<h2>Comme d&#8217;hab, commen&ccedil;ons par le mod&egrave;le</h2>
<p>Je voulais trouver un outil capable de g&eacute;rer un backlog de produit &agrave; la scrum, histoire de communiquer avec mes clients &agrave; distance. Cependant, malgr&eacute; l&#8217;existence d&#8217;<a href="http://www.icescrum.org/">excellents outils</a> d&eacute;di&eacute;s &agrave; cette <a href="http://www.aubryconseil.com/">sympathique m&eacute;thodologie agile</a>, je n&#8217;ai pas r&eacute;ussi &agrave; trouver quelque chose de vraiment simple et r&eacute;pondant &agrave; mes besoins. Alors, en bon geek, j&#8217;ai choisi de coder le mien.</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">Project:
  actAs:
    Sluggable:
      fields: [ title ]
      unique: true
&nbsp;
  columns:
    id: { type: integer, primary: true, autoincrement: true }
    title: { type: string(255), notnull: true }
&nbsp;
Story:
  actAs:
    Timestampable: ~
&nbsp;
  columns:
    id: { type: integer, primary: true, autoincrement: true }
    project_id: { type: integer, notnull: true }
    description: { type: clob, notnull: true }
    priority: { type: integer(2), default: 0 }
    effort: { type: integer(2), default: 0 }
&nbsp;
  relations:
    Project:
      foreignAlias: Stories
      local: project_id
      foreign: id
      type: one
      foreignType: many</pre></div></div>

<p>Pour les paresseux, je vous colle aussi les fixtures&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">&nbsp;
Project:
  demo:
    title: 'Demo project'
&nbsp;
Story:
  s1:
    description: 'En tant qu''anonyme, je peux m''inscrire sur le site pour devenir membre'
    priority: 1
    effort: 5
    Project: demo
&nbsp;
  s2:
    description: 'En tant que membre, je dispose d''une page d''accueil pour éditer mon profil et voir l''activité de mon réseau'
    priority: 3
    effort: 13
    Project: demo
&nbsp;
  s3:
    description: 'En tant que rédacteur, je peux écrire des articles de type magazine et les publier dans des catégories'
    priority: 2
    effort: 25
    Project: demo</pre></div></div>

<p>Voil&agrave; pour le mod&egrave;le. Je vous laisse construire tout &ccedil;a, vous connaissez le topo. Cr&eacute;ez ensuite un module &laquo;&nbsp;&nbsp;project&nbsp;&nbsp;&raquo;, avec une action &laquo;&nbsp;&nbsp;show&nbsp;&nbsp;&raquo; qui affichera une liste de users stories. Je vous passe le code de l&#8217;action qui n&#8217;a rien de sp&eacute;cial. Dans le template &laquo;&nbsp;&nbsp;showSuccess.php&nbsp;&nbsp;&raquo; du module project, ajoutez&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">// bla bla bla
&lt;div id=&quot;stories&quot;&gt;
<span class="kw2">&lt;?php</span> include_partial<span class="br0">&#40;</span><span class="st_h">'story/list'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'stories'</span> <span class="sy0">=&gt;</span> <span class="re0">$project</span><span class="sy0">-&gt;</span><span class="me1">getStories</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/div&gt;</pre></div></div>

<p>Vous aurez bien entendu surcharg&eacute; la fonction &laquo;&nbsp;&nbsp;getStories&nbsp;&nbsp;&raquo; pour trier les histoires par priorit&eacute;.</p>
<p>Cr&eacute;ez ensuite un module &laquo;&nbsp;&nbsp;story&nbsp;&nbsp;&raquo;, et ajoutez-y un template &laquo;&nbsp;&nbsp;_list.php&nbsp;&nbsp;&raquo; &hellip;</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">&lt;table class=&quot;stories&quot;&gt;
&lt;tbody&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$stories</span> <span class="kw1">as</span> <span class="re0">$story</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
    &lt;tr class=&quot;story&quot; id=&quot;story_<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$story</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&quot;&gt;
      <span class="kw2">&lt;?php</span> include_partial<span class="br0">&#40;</span><span class="st_h">'story/detail'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'story'</span> <span class="sy0">=&gt;</span> <span class="re0">$story</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
    &lt;/tr&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">endforeach</span> <span class="sy1">?&gt;</span>
&lt;/tbody&gt;
&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;#id&lt;/th&gt;
    &lt;th&gt;Description&lt;/th&gt;
    &lt;th&gt;Effort&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;</pre></div></div>

<p>Ainsi qu&#8217;un autre template &laquo;&nbsp;&nbsp;_detail.php&nbsp;&nbsp;&raquo;</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">&lt;td&gt;
  &lt;a href=&quot;#&quot; class=&quot;sort-button fg-button fg-button-icon-left ui-state-default ui-corner-all&quot;&gt;
    &lt;span class=&quot;ui-icon ui-icon-arrowthick-2-n-s&quot;&gt;&lt;/span&gt;
    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$story</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  &lt;a&gt;
&lt;/td&gt;
&lt;td&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$story</span><span class="sy0">-&gt;</span><span class="me1">getDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/td&gt;
&lt;td&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$story</span><span class="sy0">-&gt;</span><span class="me1">getEffort</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/td&gt;</pre></div></div>

<p>Vous voil&agrave; donc avec une belle liste de users stories, affich&eacute;es par ordre de priorit&eacute;, et que vous souhaiteriez pouvoir r&eacute;ordonner par drag&#8217;n'drop.</p>
<h2>Des p&#8217;tits tris, des p&#8217;tits tris, encore des p&#8217;tits tris&hellip;</h2>
<p>Dans le r&eacute;pertoire web, ajoutez dans votre fichier js maison (cr&eacute;ez le s&#8217;il n&#8217;existe pas) le code suivant.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$<span class="br0">&#40;</span>document<span class="br0">&#41;</span>.<span class="me1">ready</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  $<span class="br0">&#40;</span><span class="st0">&quot;#stories table tbody&quot;</span><span class="br0">&#41;</span>.<span class="me1">sortable</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
    <span class="co1">// limitons les déplacements sur l'axe des ordonnées, ce sera plus propre</span>
    axis<span class="sy0">:</span> <span class="st0">'y'</span><span class="sy0">,</span>
&nbsp;
    <span class="co1">// Il faut cliquer sur cet élément pour pouvoir initier le drag'n'drop</span>
    handle<span class="sy0">:</span> <span class="st0">'.sort-button'</span><span class="sy0">,</span>
&nbsp;
    <span class="co1">// Créons un joli trou stylé lors des déplacements</span>
    placeholder<span class="sy0">:</span> <span class="st0">'ui-state-highlight'</span><span class="sy0">,</span>
    forcePlaceholderSize<span class="sy0">:</span> <span class="kw2">true</span><span class="sy0">,</span>
&nbsp;
    <span class="co1">// Cette fonction permet à notre ligne de conserver son formatage lors du déplacement</span>
    <span class="co1">// Pas vraiment utile, mais plus agréable à l'œil</span>
    helper<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="sy0">,</span> tr<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="kw2">var</span> $originals <span class="sy0">=</span> tr.<span class="me1">children</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="kw2">var</span> $helper <span class="sy0">=</span> tr.<span class="me1">clone</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      $helper.<span class="me1">children</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">each</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span>index<span class="br0">&#41;</span>
      <span class="br0">&#123;</span>
        <span class="co1">// Set helper cell sizes to match the original sizes</span>
        $<span class="br0">&#40;</span><span class="kw1">this</span><span class="br0">&#41;</span>.<span class="me1">width</span><span class="br0">&#40;</span>$originals.<span class="me1">eq</span><span class="br0">&#40;</span>index<span class="br0">&#41;</span>.<span class="me1">width</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="kw1">return</span> $helper<span class="sy0">;</span>
    <span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp;
    <span class="co1">// La fonction appelée quand un élément change de position</span>
    <span class="co1">// C'est le code vraiment utile, en fait</span>
    update<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>event<span class="sy0">,</span> ui<span class="br0">&#41;</span><span class="br0">&#123;</span>
      <span class="co1">// Construit un tableau des ids des stories</span>
      serial <span class="sy0">=</span> $<span class="br0">&#40;</span><span class="kw1">this</span><span class="br0">&#41;</span>.<span class="me1">sortable</span><span class="br0">&#40;</span><span class="st0">'serialize'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
      <span class="co1">// Appelle une action en ajax</span>
      $.<span class="me1">ajax</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
        url<span class="sy0">:</span> updateorderurl<span class="sy0">,</span> <span class="co1">// set in layout.php</span>
        type<span class="sy0">:</span> <span class="st0">&quot;post&quot;</span><span class="sy0">,</span>
        data<span class="sy0">:</span> serial<span class="sy0">,</span>
        error<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
          <span class="kw3">alert</span><span class="br0">&#40;</span><span class="st0">&quot;Error ! Order not updated&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>Remarquez que la variable &laquo;&nbsp;&nbsp;updateorderurl&nbsp;&nbsp;&raquo; contient l&#8217;url de l&#8217;action qui va r&eacute;aliser la r&eacute;affectation des priorit&eacute;s. Comme cette url est g&eacute;n&eacute;r&eacute;e par Symfony, elle est d&eacute;finie dans le contr&ocirc;leur, puis affect&eacute;e &agrave; une variable javascript  dans la layout gr&acirc;ce &agrave; un slot. &Ccedil;a vaut ce que &ccedil;a vaut.</p>
<p>Normalement, vous devriez maintenant &ecirc;tre capable de changer l&#8217;ordre des stories c&ocirc;t&eacute; frontend. Bien entendu, le code m&eacute;tier charg&eacute; de g&eacute;rer le r&eacute;ordonnancement n&#8217;existe pas encore.</p>
<h2>Au c&oelig;ur du m&eacute;tier</h2>
<p>Cr&eacute;ons donc une nouvelle action dans le module &laquo;&nbsp;&nbsp;story&nbsp;&nbsp;&raquo;.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">  <span class="kw2">public</span> <span class="kw2">function</span> executeUpdateOrder<span class="br0">&#40;</span>sfWebRequest <span class="re0">$request</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="co1">// Il nous faut un moyen de récupérer le projet en question</span>
    <span class="re0">$project</span> <span class="sy0">=</span> Doctrine<span class="sy0">::</span><span class="me2">getTable</span><span class="br0">&#40;</span><span class="st_h">'project'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'project_id'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">forward404Unless</span><span class="br0">&#40;</span><span class="re0">$project</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// Correspond à la variable 'serial' dans le js, vous vous souvenez ?</span>
    <span class="co1">// C'est un simple tableau d'ids</span>
    <span class="re0">$order</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'story'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$project</span><span class="sy0">-&gt;</span><span class="me1">updateStoriesOrder</span><span class="br0">&#40;</span><span class="re0">$order</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">return</span> sfView<span class="sy0">::</span><span class="me2">HEADER_ONLY</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div>

<p>Nous revoil&agrave; repartis dans le mod&egrave;le. &Eacute;ditons notre classe Project.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/model/doctrine/Project.class.php</span>
<span class="co1">// …</span>
  <span class="co4">/**
   * Update the stories order
   *
   * @param array $order An array with the stories ids, sorted by priority
   **/</span>
  <span class="kw2">public</span> <span class="kw2">function</span> updateStoriesOrder<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="re0">$order</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$order</span> <span class="kw1">as</span> <span class="re0">$priority</span> <span class="sy0">=&gt;</span> <span class="re0">$storyId</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="re0">$story</span> <span class="sy0">=</span> Doctrine<span class="sy0">::</span><span class="me2">getTable</span><span class="br0">&#40;</span><span class="st_h">'story'</span><span class="br0">&#41;</span>
        <span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$storyId</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
      <span class="kw1">if</span><span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$story</span> <span class="sy0">||</span> <span class="re0">$story</span><span class="sy0">-&gt;</span><span class="me1">getProjectId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
        throw <span class="kw2">new</span> Exception<span class="br0">&#40;</span><span class="st_h">'moo'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
      <span class="re0">$story</span><span class="sy0">-&gt;</span><span class="me1">setPriority</span><span class="br0">&#40;</span><span class="re0">$priority</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="re0">$story</span><span class="sy0">-&gt;</span><span class="me1">save</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span></pre></div></div>

<p>Tadaaaaaam<span class="fine">&nbsp;</span>! &Ccedil;a devrait fonctionner. Voil&agrave;, c&#8217;est tout. Tiens, au moment o&ugrave; je finis d&#8217;&eacute;crire ces lignes, je m&#8217;aper&ccedil;ois qu&#8217;un <a href="http://www.symfony-project.org/plugins/sfDoctrineJQueryUISortablePlugin">plugin cens&eacute; faire exactement la m&ecirc;me chose</a> vient de sortir. Frustration. Bon, tant pis, bon week-end quand m&ecirc;me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/tutos/435-creer-une-liste-triable-avec-symfony-et-jquery-ui/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Trier un tableau de nombres avec Javascript</title>
		<link>http://www.miximum.fr/methodes-et-outils/68-trier-un-tableau-de-nombres-avec-javascript</link>
		<comments>http://www.miximum.fr/methodes-et-outils/68-trier-un-tableau-de-nombres-avec-javascript#comments</comments>
		<pubDate>Tue, 17 Jun 2008 09:04:05 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Méthodes et outils]]></category>
		<category><![CDATA[astuce]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[snippet]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=68</guid>
		<description><![CDATA[J&#8217;adore javascript. Je l&#8217;avoue. Malgr&#233; sa syntaxe parfois compl&#232;tement tordue, malgr&#233; son m&#233;pris total pour le principe de moindre suprise, malgr&#233; son niveau &#233;lev&#233; sur l&#8217;&#233;chelle du WTF, ce langage a un petit quelque chose qui me pla&#238;t bien. C&#8217;est comme pour les personnes, on a les atomes crochus, ou on ne les a pas. [...]]]></description>
			<content:encoded><![CDATA[<p>J&#8217;adore javascript. Je l&#8217;avoue. Malgr&eacute; sa syntaxe parfois compl&egrave;tement tordue, malgr&eacute; son m&eacute;pris total pour <a href="http://fr.wikipedia.org/wiki/Principe_de_moindre_surprise">le principe de moindre suprise</a>, malgr&eacute; son <a href="http://www.flickr.com/photos/smitty/2245445147/">niveau &eacute;lev&eacute; sur l&#8217;&eacute;chelle du WTF</a>, ce langage a un petit quelque chose qui me pla&icirc;t bien. C&#8217;est comme pour les personnes, on a les atomes crochus, ou on ne les a pas.</p>
<p>D&#8217;ailleurs, dans le genre de surprise qu&#8217;on peut avoir en codant, j&#8217;ai &eacute;t&eacute; joliment &eacute;tonn&eacute; en voulant <strong>trier un tableau de nombres</strong>.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">var</span> nombres <span class="sy0">=</span> <span class="kw2">new</span> Array<span class="br0">&#40;</span><span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">5</span><span class="sy0">,</span> <span class="nu0">8</span><span class="sy0">,</span> <span class="nu0">9</span><span class="sy0">,</span> <span class="nu0">12</span><span class="sy0">,</span> <span class="nu0">16</span><span class="br0">&#41;</span><span class="sy0">;</span>
nombres.<span class="me1">sort</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw3">alert</span><span class="br0">&#40;</span>nombres<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="co1">// Et on obtient :</span>
<span class="co1">// 1, 12, 16, 2, 5, 8, 9</span></pre></div></div>

<p>G&eacute;nial<span class="fine">&nbsp;</span>! La fonction sort de l&#8217;objet Array tri les &eacute;l&eacute;ments par <a href="http://fr.wikipedia.org/wiki/Ordre_lexicographique">ordre lexicographique</a> (&agrave; ne pas confondre avec l&#8217;<a href="http://fr.wikipedia.org/wiki/Ordre_alphab%C3%A9tique">ordre alphab&eacute;tique</a>)<span class="fine">&nbsp;</span>!</p>
<p>Bon, et comment je fais, moi, pour trier mon tableau de nombre par ordre croissant<span class="fine">&nbsp;</span>? Allez, je suis sympa, je vous donne la solution&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw2">function</span> compare<span class="br0">&#40;</span>x<span class="sy0">,</span> y<span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span> x <span class="sy0">-</span> y<span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">var</span> nombres <span class="sy0">=</span> <span class="kw2">new</span> Array<span class="br0">&#40;</span><span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">5</span><span class="sy0">,</span> <span class="nu0">8</span><span class="sy0">,</span> <span class="nu0">9</span><span class="sy0">,</span> <span class="nu0">12</span><span class="sy0">,</span> <span class="nu0">16</span><span class="br0">&#41;</span><span class="sy0">;</span>
nombres.<span class="me1">sort</span><span class="br0">&#40;</span>compare<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw3">alert</span><span class="br0">&#40;</span>nombres<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="co1">// Et on obtient bien :</span>
<span class="co1">// 1, 2, 5, 8, 9, 12, 16</span>
&nbsp;
<span class="co1">// Pour trier par ordre décroissant, on definira autrement la fonction compare :</span>
&nbsp;
<span class="kw2">function</span> compare<span class="br0">&#40;</span>x<span class="sy0">,</span> y<span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span> y <span class="sy0">-</span> x<span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Tellement simple. Tellement tordu. Tellement inattendu. J&#8217;adore. Je dois &ecirc;tre un peu sado-maso sur les bords.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/methodes-et-outils/68-trier-un-tableau-de-nombres-avec-javascript/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

