<?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>jQuery &#8211; Roy Duineveld</title>
	<atom:link href="https://royduineveld.nl/tag/jquery/feed/" rel="self" type="application/rss+xml" />
	<link>https://royduineveld.nl</link>
	<description>Waarom moeilijk doen als het makkelijk kan?</description>
	<lastBuildDate>Tue, 27 Jan 2026 07:48:00 +0000</lastBuildDate>
	<language>nl</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.9.26</generator>
	<item>
		<title>Pijltjes op de collapse / accordion van Twitter Bootstrap</title>
		<link>https://royduineveld.nl/pijltjes-collapse-accordion-twitter-bootstrap/</link>
		<comments>https://royduineveld.nl/pijltjes-collapse-accordion-twitter-bootstrap/#comments</comments>
		<pubDate>Sun, 01 Sep 2013 14:09:21 +0000</pubDate>
		<dc:creator><![CDATA[Roy Duineveld]]></dc:creator>
				<category><![CDATA[Tips & Trucs]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Twitter Bootstrap]]></category>

		<guid isPermaLink="false">https://royduineveld.nl/?p=515</guid>
		<description><![CDATA[<p>Recent kreeg ik feedback op een website die ik in het verleden gemaakt had waarbij de collapse van Twitter Bootstrap gebruikt wordt, de opmerking was dat het niet duidelijk genoeg...</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/pijltjes-collapse-accordion-twitter-bootstrap/">Pijltjes op de collapse / accordion van Twitter Bootstrap</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Recent kreeg ik feedback op een website die ik in het verleden gemaakt had waarbij de <a title="Ga naar de collapse documentatie" href="http://getbootstrap.com/2.3.2/javascript.html#collapse" target="_blank">collapse</a> van Twitter Bootstrap gebruikt wordt, de opmerking was dat het niet duidelijk genoeg was dat deze opengeklapt kunnen worden door aan te klikken. Zodoende hier pijltjes aan toegevoegd welke verdwijnen zodra er één geopend is. Hieronder zal ik uitleggen wat ik hiervoor aangepast heb.</p>
<p><a href="https://royduineveld.nl/wp-content/uploads/2013/09/collapse.png"><img class="aligncenter size-large wp-image-516" alt="Twitter Bootstrap Collapse" src="https://royduineveld.nl/wp-content/uploads/2013/09/collapse-1024x434.png" width="550" height="233" srcset="https://royduineveld.nl/wp-content/uploads/2013/09/collapse-1024x434.png 1024w, https://royduineveld.nl/wp-content/uploads/2013/09/collapse-300x127.png 300w, https://royduineveld.nl/wp-content/uploads/2013/09/collapse.png 1184w" sizes="(max-width: 550px) 100vw, 550px" /></a></p>
<h2>HTML aanpassen</h2>
<p>Voeg aan elke &#8220;accordion-heading&#8221; een afbeelding van een pijltje toe met een &#8220;pull-left&#8221;.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;div class=&quot;accordion-heading&quot;&gt;
	&lt;h2&gt;&lt;i class=&quot;icon-chevron-down pull-left&quot;&gt;&lt;/i&gt; &lt;a class=&quot;accordion-toggle&quot; data-toggle=&quot;collapse&quot; data-parent=&quot;#wizard&quot; href=&quot;#brand&quot;&gt;Merk&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
</pre>
<h2>CSS toevoegen</h2>
<p>Zoals hierboven in de HTML te zien is heb ik heading 2 tags gebruikt, hier moest de margin voor het icoon dan ook op aangepast worden:</p>
<pre class="brush: css; title: ; notranslate">
.accordion .icon-chevron-down {
	margin: 9px 10px 0 15px;
}
</pre>
<h2>Javascript toevoegen</h2>
<p>Om het allemaal goed te laten functioneren heb ik een stukje Javascript toegevoegd welke inhaakt op de Javascript van de collapse. Zoals te zien wordt hier jQuery bij gebruikt.</p>
<pre class="brush: jscript; title: ; notranslate">
$('#wizard').on('show', function (e) {
	$('.accordion .icon-chevron-down').removeClass('hide');
	$(e.target).prev().children().children('.icon-chevron-down').addClass('hide');
});

$('#wizard').on('hide', function (e) {
	$('.accordion .icon-chevron-down').removeClass('hide');
});
</pre>
<blockquote><p>Mocht iemand zich geroepen voelen dit te melden bij Twitter Boostrap als toevoeging, ga je gang!</p></blockquote>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/pijltjes-collapse-accordion-twitter-bootstrap/">Pijltjes op de collapse / accordion van Twitter Bootstrap</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://royduineveld.nl/pijltjes-collapse-accordion-twitter-bootstrap/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Waardes behouden na verzenden van dynamisch formulier</title>
		<link>https://royduineveld.nl/waardes-behouden-na-verzenden-van-dynamisch-formulier/</link>
		<comments>https://royduineveld.nl/waardes-behouden-na-verzenden-van-dynamisch-formulier/#respond</comments>
		<pubDate>Mon, 13 May 2013 18:19:53 +0000</pubDate>
		<dc:creator><![CDATA[Roy Duineveld]]></dc:creator>
				<category><![CDATA[Tips & Trucs]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Local Storage]]></category>
		<category><![CDATA[Session Storage]]></category>

		<guid isPermaLink="false">https://royduineveld.nl/?p=449</guid>
		<description><![CDATA[<p>Na het verzenden én vervolgens op de &#8220;vorige knop&#8221; geklikt te hebben zijn alle ingevulde waardes van een dynamisch formulier verdwenen. Ofwel, een formulier waarbij met Javascript elementen toegevoegd worden....</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/waardes-behouden-na-verzenden-van-dynamisch-formulier/">Waardes behouden na verzenden van dynamisch formulier</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Na het verzenden én vervolgens op de &#8220;vorige knop&#8221; geklikt te hebben zijn alle ingevulde waardes van een dynamisch formulier verdwenen. Ofwel, een formulier waarbij met Javascript elementen toegevoegd worden. Om dit op te lossen zijn er meerdere mogelijkheden:</p>
<ul>
<li><span style="line-height: 13px;">Formulier middels Ajax verzenden, zodat de pagina niet opnieuw geladen hoeft te worden</span></li>
<li>De waardes middels Ajax opslaan en opnieuw inladen</li>
<li>De gegevens lokaal opslaan, dit voor het verzenden</li>
</ul>
<p>Ik heb recent gekozen voor de laatste optie. Voordat ik de oplossing hiervoor laat zien, eerst wat materiaal om mee te werken. Laten we een eenvoudig formulier nemen:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;form action=&quot;&quot; method=&quot;POST&quot;&gt;
	&lt;table&gt;
		&lt;tr id=&quot;eerste-regel&quot;&gt;
			&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;name[]&quot; placeholder=&quot;Naam...&quot;&gt;&lt;/td&gt;
			&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;number[]&quot; placeholder=&quot;Nummer...&quot;&gt;&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;
	&lt;a href=&quot;#&quot; id=&quot;regel-toevoegen&quot;&gt;Regel toevoegen&lt;/a&gt; &lt;input type=&quot;submit&quot; value=&quot;Verzenden!&quot;&gt;
&lt;/form&gt;
</pre>
<p>Het volgende stukje Javascript in samenwerking met jQuery zorgt ervoor dat wanneer er op &#8220;Regel toevoegen&#8221; geklikt wordt er een nieuwe regel bij komt:</p>
<pre class="brush: jscript; title: ; notranslate">
// Regel toevoegen geklikt?
$('#regel-toevoegen').click(function()
{
	// Eerste regel ophalen
	var regel = $('#eerste-regel').clone();

	// ID verwijderen
	regel.removeAttr('id');

	// Ingevulde waardes verwijderen
	regel.find('input').val('');

	// Nieuwe regel toevoegen en het ID en de ingevulde waardes verwijderen
	$('table').append( regel );

	// False terug sturen zodat de pagina niet verspringt
	return false;
});
</pre>
<p>Hier kunnen we op verder bouwen! Want wanneer je meerdere regels toevoegt, deze invult en na het klikken op &#8220;Verzenden!&#8221; terug gaat; is al je kostbare werk verloren gegaan. Om de gegevens voordat deze verzonden worden op te slaan, dienen we dit af te vangen waarna we deze gestructureerd op kunnen slaan. Zie het volgende stukje code:</p>
<pre class="brush: jscript; title: ; notranslate">
// Form versturen?
$('form').submit(function()
{
	// Object met array's maken
	var array           = {};
	array['name']       = [];
	array['number']		= [];
	array['counter']    = 0;

	// Door alle tabel regels loopen
	$('tr').each(function()
	{
		array['name'].push( $(this).find('input[name=&quot;name[]&quot;]').val() );
		array['number'].push( $(this).find('input[name=&quot;number[]&quot;]').val() );
		array['counter']++;
	});

	// Opslaan in session storage
	sessionStorage.setItem('input', JSON.stringify(array));
});
</pre>
<p>Eerst vangen we de &#8220;submit&#8221; af, hierna bouwen we een object op met array&#8217;s gevolgd door alle ingevulde waardes hierin te zetten. Tevens draait er een tellertje mee om het aantal velden te bepalen. Als laatste worden de gegevens opgeslagen in &#8220;Session Storage&#8221;. In cookies kan je weinig kwijt en &#8220;Local Storage&#8221; bewaard de gegevens ook nadat het browser venster gesloten is, vandaar deze keuze. Let daarbij wel op dat je geen object of array in session of local storage kan opslaan. Hiervoor dient deze eerst omgezet te worden naar een &#8220;string&#8221;, vandaar de &#8220;stringify&#8221; functie. Hartstikke mooi dat het opgeslagen is, maar het moet er ook weer uit natuurlijk! Zie:</p>
<pre class="brush: jscript; title: ; notranslate">
// Iets in session storage aanwezig?
if(sessionStorage.getItem('input'))
{
	// Gegevens ophalen
	var array = JSON.parse( sessionStorage.getItem('input') );

	// Nieuwe regels toevoegen, minus de al aanwezige
	for (var n = 0; n &lt; (array['counter'] - 1); ++ n)
	{
		$('#regel-toevoegen').click();
	}

	// Door alle tabel regels loopen
	$('tr').each(function(index,value)
	{
		// Waarde plaatsen
		$(this).find('input[name=&quot;name[]&quot;]').val( array['name'][index] );
		$(this).find('input[name=&quot;number[]&quot;]').val( array['number'][index] );
	});

	// Waardes weer verwijderen
	sessionStorage.removeItem('input');
}
</pre>
<p>Eerst maar kijken of er iets aanwezig is, wanneer dat het geval is de gegevens ophalen en van de &#8220;string&#8221; weer een object met array&#8217;s maken. De teller laten lopen en elke keer even op de &#8220;Regel toevoegen&#8221; knop klikken. Vervolgens het zelfde stukje als bij het opslaan, enkel plaatsen we nu de gegevens terug in plaats van dat we deze uitlezen. Als toetje de gegevens nog even verwijderen en klaar!</p>
<p><a href="https://royduineveld.nl/demos/waardes-behouden-na-verzenden/" class="demo-button" target="_blank">Klik hier voor een online demo</a></p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/waardes-behouden-na-verzenden-van-dynamisch-formulier/">Waardes behouden na verzenden van dynamisch formulier</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://royduineveld.nl/waardes-behouden-na-verzenden-van-dynamisch-formulier/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>App maken met Phonegap en Phonegap Build</title>
		<link>https://royduineveld.nl/app-maken-met-phonegap-en-phonegap-build/</link>
		<comments>https://royduineveld.nl/app-maken-met-phonegap-en-phonegap-build/#comments</comments>
		<pubDate>Tue, 30 Apr 2013 13:26:47 +0000</pubDate>
		<dc:creator><![CDATA[Roy Duineveld]]></dc:creator>
				<category><![CDATA[Tips & Trucs]]></category>
		<category><![CDATA[Cordova]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Phonegap]]></category>

		<guid isPermaLink="false">https://royduineveld.nl/?p=413</guid>
		<description><![CDATA[<p>Phonegap maakt het mogelijk om super eenvoudig een app te maken met HTML, CSS en Javascript. Dit voor verschillende mobiele platformen als onder andere Android, iOS, Blackberry OS en Windows...</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/app-maken-met-phonegap-en-phonegap-build/">App maken met Phonegap en Phonegap Build</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Phonegap maakt het mogelijk om super eenvoudig een app te maken met HTML, CSS en Javascript. Dit voor verschillende mobiele platformen als onder andere Android, iOS, Blackberry OS en Windows Phone. Als je dit voor het eerste hoort zal je denken dat het géén native app is en dus géén functionaliteiten (camera, bestandssysteem, notificaties, enz) kan gebruiken van de telefoon (ik houd het in dit artikel op telefoon, maar hiermee bedoel ik natuurlijk ook tablet). Dit kan juist wél! Om eerst de verschillen even uit te leggen tussen navtive-, web-, en hybride apps:</p>
<h2>Soorten apps</h2>
<h3>Native app</h3>
<blockquote><p>Een platform afhankelijk applicatie. Niet bij elk platform kan je in eenzelfde programmeer taal ontwikkelen en dus zal je voor elk platform een totaal nieuwe app moeten maken. Daarin tegen kan je met een native app wél alle mogelijkheden van een telefoon benutten en is er géén internet noodzakelijk om te functioneren.</p></blockquote>
<h3>Web app</h3>
<blockquote><p>Simpel gezegd; een website in een app jasje, alsof het een echte app is. Een mobiele website wordt ook wel eens een web app genoemd. Nadeel is dat géén functionaliteiten van de telefoon aangesproken kunnen worden en dat wanneer er geen internet is deze niet functioneert. (in een ander artikel heb een methode beschreven om een website wél offline beschikbaar te maken: <a title="Website offline beschikbaar maken met een submit fallback" href="https://royduineveld.nl/html/47/website-offline-beschikbaar-maken-met-een-submit-fallback/">Website offline beschikbaar maken met een submit fallback</a>)</p></blockquote>
<h3>Hybride app</h3>
<blockquote><p>Een combinatie van een native app en een web app waarbij dus vrijwel alles mogelijk is. Nadeel is dat er ook twee omgevingen bijgehouden dienen te worden, zowel het native als het web gedeelte.</p></blockquote>
<h2>Wat is Phonegap?</h2>
<p>Phonegap is een distributie van <a title="Ga naar Apache Cordova" href="http://cordova.apache.org/" target="_blank">Apache Cordova</a>. Phonegap maakt het ten opzichte van Cordova enkel wat makkelijker met <a title="Ga naar Phonegap Build" href="https://build.phonegap.com/" target="_blank">Phonegap Build</a> en &#8220;<a title="Ga naar de documentantie over Phonegap Hydration" href="https://build.phonegap.com/docs/hydration" target="_blank">hydration</a>&#8220;. Met Phonegap een app maken behoort tot een hybride app. Phonegap ofwel Cordova is dan het native gedeelte. Dit zorgt ervoor dat via Javascript functionaliteiten van de telefoon aangesproken kunnen worden. Benieuwd welke apps met Phonegap gemaakt zijn? Kijk eens <a title="Ga naar een overzicht van met Phonegap gemaakte apps" href="http://phonegap.com/app/" target="_blank">hier</a>.</p>
<h3>Wat is Phonegap Build?</h3>
<p>Dit maakt het mogelijk om je HTML, CSS en Javascript in te voeren en vervolgens zorgt de Build service ervoor dat er apps uit komen. In het geval van Android dus een apk bestand. Ter verduidelijking:</p>
<p><a href="https://royduineveld.nl/wp-content/uploads/2013/04/build-diagram1.png"><img class="aligncenter size-large wp-image-416" alt="Phonegap Build" src="https://royduineveld.nl/wp-content/uploads/2013/04/build-diagram1-1024x353.png" width="550" height="189" srcset="https://royduineveld.nl/wp-content/uploads/2013/04/build-diagram1-1024x353.png 1024w, https://royduineveld.nl/wp-content/uploads/2013/04/build-diagram1-300x103.png 300w, https://royduineveld.nl/wp-content/uploads/2013/04/build-diagram1.png 1450w" sizes="(max-width: 550px) 100vw, 550px" /></a></p>
<h3>Wat is Hydration?</h3>
<p>Tijdens het testen van een app, in het geval van Android; dien je elke keer een apk op je telefoon te zetten en vervolgens de al aanwezige cq oude app te updaten. Hydration maakt het mogelijk om updates te &#8220;pushen&#8221;. Door de app opnieuw te starten wordt automatisch de nieuwe versie gedownload en gebruikt. Eventueel kan je ook met <a title="Ga naar de Ripple Phonegap Emulator" href="http://emulate.phonegap.com/" target="_blank">Ripple</a> werken, dit is een emulator. Om de emulator te gebruiken dient wel je app &#8220;te draaien&#8221; ofwel lokaal middels bijvoorbeeld <a title="Ga naar Xampp" href="http://www.apachefriends.org/en/xampp.html" target="_blank">XAMPP</a> of simpelweg bij je hosting partij. Van Ripple is ook een <a title="Ga naar Ripple Emulator Google Chrome extensie" href="https://chrome.google.com/webstore/detail/ripple-emulator-beta/geelfhphabnejjhdalkjhgipohgpdnoc" target="_blank">extensie</a> beschikbaar voor Google Chrome.</p>
<h2>Eindelijk, beginnen!</h2>
<p>Eerst maar een <a title="Ga naar Phonegap Build om een account aan te maken" href="https://build.phonegap.com/plans/free" target="_blank">account aanmaken</a> bij Phonegap Build. Hierna <a title="Download Phonegap start" href="https://github.com/phonegap/phonegap-start/archive/master.zip" target="_blank">downloaden</a> we <a title="Ga naar de Phonegap start github pagina" href="https://github.com/phonegap/phonegap-start" target="_blank">phonegap-start</a>. Hierin zitten alle basis elementen voor een app. Dit is een soort van boilerplate als ook voor html beschikbaar is: <a title="Ga naar HTML 5 Boilerplate" href="http://html5boilerplate.com/" target="_blank">HTML5Boilerplate</a>. Na het downloaden en uitpakken van phonegap-start; pakken we alles gelijk weer in, maar enkel de bestanden in de www map. Terug naar de browser en de Phonegap Build website waar we een nieuwe app gaan maken. Hierbij krijg je de keuze om een open-source app te maken waarbij je de code op Github beschikbaar stelt. De andere optie is een &#8220;private&#8221; app, eventueel ook via Github te regelen. Wij kiezen voor zelf een zip bestand uploaden waarbij we het zojuist gemaakte zip bestand kiezen.</p>
<p><a href="https://royduineveld.nl/wp-content/uploads/2013/04/phonegap-new-app.png"><img class="aligncenter size-large wp-image-418" alt="Phonegap nieuwe app maken" src="https://royduineveld.nl/wp-content/uploads/2013/04/phonegap-new-app-1024x659.png" width="550" height="353" srcset="https://royduineveld.nl/wp-content/uploads/2013/04/phonegap-new-app-1024x659.png 1024w, https://royduineveld.nl/wp-content/uploads/2013/04/phonegap-new-app-300x193.png 300w, https://royduineveld.nl/wp-content/uploads/2013/04/phonegap-new-app.png 1204w" sizes="(max-width: 550px) 100vw, 550px" /></a></p>
<p>Na de upload kunnen we de eventueel debugging en hydration aanzetten. Door vervolgens op &#8220;ready to build&#8221; te klikken worden de apps voor de beschikbare platformen gemaakt! Zodra gereed krijgen de iconen van de platformen kleur en kunnen deze aangeklikt worden om de app te downloaden. In het geval van Android dus het apk bestand. Dit bestand kan je vervolgens op je telefoon zetten, makkelijker is om het QR code te scannen.</p>
<h3>App aanpassen</h3>
<p>Hartstikke leuk zo&#8217;n app die enkel &#8220;Device is Ready&#8221; zegt maar het kan niks! Om de app aan te passen beginnen we bij het config.xml bestand. Hierin staat alle informatie over de app als de naam, omschrijving, permissies en iconen. Pas dit bestand naar je wensen aan en mochten er onduidelijkheden zijn, lees de <a title="Ga naar de config.xml documentatie" href="https://build.phonegap.com/docs/config-xml" target="_blank">documentatie</a> hierover. Voordat je alle gewenste formaten iconen gaat maken voor je app, denk even na voor welke platformen je de app echt gaat gebruiken. Niet alles in het config.xml bestand is namelijk verplicht! Hierna kan je met index.html aan de gang gaan. Gebruik bijvoorbeeld <a title="Ga naar jQuery Mobile" href="http://jquerymobile.com/" target="_blank">jQuery Mobile</a> om je app er grafisch goed uit te laten zien. Eventueel kan je meerdere html bestanden maken mocht je app uit meerdere &#8220;pagina&#8217;s&#8221; bestaan. Gebruik alles wat je in huis hebt om een mooie app te maken middels HTML, CSS en Javascript. Om te testen kan je zoals eerder aangegeven Ripple gebruiken of je zipt alles in de www map nogmaals en upload dit via de &#8220;Update code&#8221; knop op de website van Phonegap Build.</p>
<h3>Telefoon functies aanspreken</h3>
<p>Ga ik nog een keer; hartstikke mooi die app maar ik wil de functies van een telefoon gebruiken! Alle informatie hierover kan je in de <a title="Ga naar de documentatie van Phonegap" href="http://docs.phonegap.com/" target="_blank">documentatie</a> van Phonegap vinden. Ik zal in dit artikel de camera aanspreken en een foto maken. Wat de permissies betreft in de documentatie, dit kan je overslaan gezien Phonegap Build dit regelt in de config.xml. Om de camera permissie te krijgen dien je de volgende regel toe te voegen in config.xml:</p>
<pre class="brush: xml; title: ; notranslate">&lt;feature name=&quot;http://api.phonegap.com/1.0/camera&quot;/&gt;</pre>
<p>Zie hiervoor &#8220;PhoneGap API Features&#8221; in de <a title="Ga naar de Phonegap Build config.xml documentatie" href="https://build.phonegap.com/docs/config-xml" target="_blank">config.xml documentatie</a>.</p>
<p>Om een foto te maken hebben we een knop nodig, na index.html wat opgeschoond te hebben zou dit er ongeveer zo uit moeten zien:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
	&lt;head&gt;
		&lt;meta charset=&quot;utf-8&quot; /&gt;
		&lt;meta name=&quot;format-detection&quot; content=&quot;telephone=no&quot; /&gt;
		&lt;meta name=&quot;viewport&quot; content=&quot;user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi&quot; /&gt;
		&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;css/index.css&quot; /&gt;
		&lt;title&gt;Foto maken&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;div class=&quot;app&quot;&gt;
			&lt;h1&gt;Foto!&lt;/h1&gt;
			&lt;button id=&quot;maak-foto&quot;&gt;Maken&lt;/button&gt;
		&lt;/div&gt;
		&lt;script type=&quot;text/javascript&quot; src=&quot;phonegap.js&quot;&gt;&lt;/script&gt;
		&lt;script type=&quot;text/javascript&quot; src=&quot;js/index.js&quot;&gt;&lt;/script&gt;
	&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Zoals je ziet worden hier twee javascript bestanden aangesproken. Wat je wellicht is opgevallen is dat phonegap.js niet aanwezig is in de map! Dit klopt, deze wordt middels de Phonegap Build toegevoegd. De vermelding dan ook gewoon laten staan om de mogelijkheden van de telefoon aan te spreken. Door naar het index.js bestand! Middels Javascript kan je uiteindelijk de functies aanspreken, bij websites maak ik graag gebruik van jQuery, laten we dat dan hier ook doen! Ga naar de website van jQuery, download de laatste versie en sla deze op in de &#8220;js&#8221; map. Vervolgens moet hier nog wel even naar gelinkt worden vanuit het index.html bestand. Voeg na het phonegap.js regel de volgende regel toe:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.js&quot;&gt;&lt;/script&gt;
</pre>
<p>Vanuit een CDN laden kan natuurlijk ook, maar om de app ook zonder internet te laten functioneren is dit nu geen goed idee. Na ook het index.js bestand wat opgeschoond te hebben en de camera documentatie doorgespit te hebben, het volgende resultaat:</p>
<pre class="brush: jscript; title: ; notranslate">
// Anonieme functie openen
(function()
{
	// Wachten tot het apparaat klaar is
	document.addEventListener('deviceready', onDeviceReady, false);

	// Het apparaat is klaar
	function onDeviceReady()
	{
		// Telefoon functies kunnen pas aangesproken worden
		// wanneer het apparaat klaar is. Ofwel wanneer deze
		// functie aangesproken wordt kunnen deze pas gebruikt
		// worden. Aangezien de gebruiker hoogst waarschijnlijk
		// niet eerder op de foto maken knop klikt dan dat het
		// apparaat klaar is, maak ik hier nu geen gebruik van.
	}

	// Foto nemen is gelukt
	function cameraSuccess(imageData)
	{
		// Na de foto maken knop de afbeelding weergeven
		$('#maak-foto').after('&lt;img src=&quot;' + &quot;data:image/jpeg;base64,&quot; + imageData + '&quot;&gt;');
	}

	// Foto nemen is mislukt
	function cameraError(message)
	{
		// Foutmelding weergeven
		alert('Er ging iets fout! ' + message);
	}

	// Op de foto maken knop geklikt
	$('#maak-foto').click(function()
	{
		// Eventueel eerder gemaakte foto verwijderen
		$('img').remove();

		// Foto maken
		navigator.camera.getPicture( cameraSuccess, cameraError, {
			quality: 50, // Foto kwaliteit
			destinationType: Camera.DestinationType.DATA_URL // Base64 gecodeerde afbeelding als resultaat
		});
	});

// Functie direct uitvoeren
})();
</pre>
<p>Dit kan natuurlijk aan alle kanten uitgebreid worden. Van netjes vormgeven tot de afbeelding middels Ajax naar een server versturen.</p>
<blockquote><p>Schoot me net te binnen en klonk wel leuk: App? Use Phonegap!</p></blockquote>
<h2>Updates</h2>
<p>11-05-2013 &#8211; Inmiddels is er een cursus beschikbaar bij Tutsplus, erg leerzaam: <a href="https://tutsplus.com/course/phone-gap-essentials/">https://tutsplus.com/course/phone-gap-essentials/</a></p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/app-maken-met-phonegap-en-phonegap-build/">App maken met Phonegap en Phonegap Build</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://royduineveld.nl/app-maken-met-phonegap-en-phonegap-build/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>PHP&#8217;s isset functie in Javascript / jQuery</title>
		<link>https://royduineveld.nl/phps-isset-functie-in-javascript-jquery/</link>
		<comments>https://royduineveld.nl/phps-isset-functie-in-javascript-jquery/#respond</comments>
		<pubDate>Mon, 11 Mar 2013 18:54:44 +0000</pubDate>
		<dc:creator><![CDATA[Roy Duineveld]]></dc:creator>
				<category><![CDATA[Tips & Trucs]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">https://royduineveld.nl/?p=334</guid>
		<description><![CDATA[<p>Een simpele functie in Javascript welke hetzelfde doet als de isset functie in PHP: Ben je opzoek naar meerdere PHP functies in Javascript? Kijk eens naar PHP.JS</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/phps-isset-functie-in-javascript-jquery/">PHP&#8217;s isset functie in Javascript / jQuery</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Een simpele functie in Javascript welke hetzelfde doet als de <a title="isset functie" href="http://php.net/isset" target="_blank">isset functie</a> in PHP:</p>
<pre class="brush: jscript; title: ; notranslate">
function isset(var)
{
	return typeof(variable) != &quot;undefined&quot; &amp;&amp; variable !== null;
}
</pre>
<blockquote><p>Ben je opzoek naar meerdere PHP functies in Javascript? Kijk eens naar <a title="PHP.JS" href="http://phpjs.org/" target="_blank">PHP.JS</a></p></blockquote>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/phps-isset-functie-in-javascript-jquery/">PHP&#8217;s isset functie in Javascript / jQuery</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://royduineveld.nl/phps-isset-functie-in-javascript-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ajax request annuleren</title>
		<link>https://royduineveld.nl/ajax-request-annuleren/</link>
		<comments>https://royduineveld.nl/ajax-request-annuleren/#respond</comments>
		<pubDate>Wed, 02 Jan 2013 19:15:00 +0000</pubDate>
		<dc:creator><![CDATA[Roy Duineveld]]></dc:creator>
				<category><![CDATA[Tips & Trucs]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">https://royduineveld.nl/?p=175</guid>
		<description><![CDATA[<p>Ajax werkt asynchroon. Dit houd in dat er meerdere verzoeken tegelijk uitgevoerd kunnen worden en de één niet wacht op de ander. Stel dat je een website hebt met product filters....</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/ajax-request-annuleren/">Ajax request annuleren</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Ajax werkt asynchroon. Dit houd in dat er meerdere verzoeken tegelijk uitgevoerd kunnen worden en de één niet wacht op de ander. Stel dat je een website hebt met <a href="http://telbat.nl/tablets-vergelijken" target="_blank">product filters</a>. Je kiest een aantal filters en je krijgt het gewenste resultaat. Prachtig, maar wanneer je op een langzame internet verbinding zit (3G) en er een filter gekozen wordt met heel veel resultaten en snel daarop volgend een filter welke maar één resultaat oplevert. Dan willen we dit in de gekozen volgorde zien. De filter met één resultaat is natuurlijk veel sneller klaar dan die met meerdere resultaten wat als resultaat geeft dat je uiteindelijk meerdere resultaten krijgt te zien, wat natuurlijk niet de bedoeling is!</p>
<p>Om dit op te lossen dient het eerste verzoek (ajax request) geannuleerd te worden wanneer deze nog bezig is. Mocht je foutmeldingen weergeven wanneer deze optreden bij een ajax verzoek dienen de geannuleerde verzoeken niet weergegeven te worden.</p>
<p>Het voorbeeld:</p>
<pre class="brush: jscript; title: ; notranslate">

//Self invoking anonymous function
//Ofwel een naamloze functie welke automatisch gestart wordt
(function()
{
	//Wachten tot een checkbox veranderd
	$('input[type=checkbox]').change(function()
	{
		//Wanneer er al een request is deze annuleren
		if ( typeof request !== &quot;undefined&quot; &amp;&amp; request) {
			request.abort();
		}

		//Ajax request
		request = $.ajax({
			url: 		'http://website.nl/',
			data: 		{ naam: 'Roy Duineveld' },
			dataType: 	'json'
			type: 		'POST',
			error: 		function(jqXHR, textStatus, errorThrown)
			{
				//Wanneer de ajax request geannuleerd wordt dit niet weergeven
				if(errorThrown != 'abort')
				{
					alert('Er ging iets fout! ' + errorThrown);
				}
			},
			succcess: 	function(data)
			{
				$('body').html(data);
			}
		});
	});
})();

</pre>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/ajax-request-annuleren/">Ajax request annuleren</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://royduineveld.nl/ajax-request-annuleren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Website offline beschikbaar maken met een submit fallback</title>
		<link>https://royduineveld.nl/website-offline-beschikbaar-maken-met-een-submit-fallback/</link>
		<comments>https://royduineveld.nl/website-offline-beschikbaar-maken-met-een-submit-fallback/#comments</comments>
		<pubDate>Thu, 15 Nov 2012 16:42:12 +0000</pubDate>
		<dc:creator><![CDATA[Roy Duineveld]]></dc:creator>
				<category><![CDATA[Tips & Trucs]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Local Storage]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">https://royduineveld.nl/?p=47</guid>
		<description><![CDATA[<p>Een website met formulier offline beschikbaar maken en de ingevoerde data verzenden wanneer weer online, dat kan middels HTML5 i.c.m. Javascript! Om de pagina offline beschikbaar te maken kan je...</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/website-offline-beschikbaar-maken-met-een-submit-fallback/">Website offline beschikbaar maken met een submit fallback</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Een website met formulier offline beschikbaar maken en de ingevoerde data verzenden wanneer weer online, dat kan middels HTML5 i.c.m. Javascript! Om de pagina offline beschikbaar te maken kan je gebruik maken van de standaard cache methodes. Nadeel hiervan is dat wanneer je de pagina opnieuw laad je toch ineens een foutpagina krijgt. Beter gebruik je een <a href="http://www.w3.org/TR/html5/offline.html#manifests">cache manifest</a> (werkt in alle browsers en helaas, zoals gewoonlijk, weer niet in Internet Explorer). Een voorbeeld pagina met een formulier (index.php) waarvan de inhoud simpelweg naar een tekst bestand geschreven wordt:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
//Form &quot;gesubmit&quot;?
if($_POST)
{
	//Velden scheiden door een komma en achteraan data.txt toevoegen
	file_put_contents('data.txt', implode(', ',$_POST).&quot;\n&quot;, FILE_APPEND);

	//Pagina opnieuw laden
	header('Location: index.php');
}
?&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;meta charset=&quot;utf-8&quot;&gt;
	&lt;title&gt;Pagina naam&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

	&lt;form method=&quot;post&quot; action=&quot;&quot;&gt;

		&lt;input type=&quot;text&quot; name=&quot;inputname1&quot; /&gt;
		&lt;input type=&quot;text&quot; name=&quot;inputname2&quot; /&gt;

		&lt;input type=&quot;submit&quot; value=&quot;Opslaan!&quot; /&gt;

	&lt;/form&gt;

	&lt;p&gt;Data:&lt;/p&gt;
	&lt;hr /&gt;
	&lt;?php
	//Gegevens ophalen uit data.txt, om XSS te voorkomen door htmlspecialchars halen en als laatste middels nl2br ervoor zorgen dat de &quot;enters&quot; ofwel nieuwe lijnen/regels zichtbaar zijn.
	echo nl2br(htmlspecialchars(file_get_contents('data.txt')));
	?&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<h2>Manifest bestand</h2>
<p>Een cache manifest daaraan toevoegen, simpelweg de html tag vervangen door:</p>
<pre class="brush: xml; title: ; notranslate">&lt;html manifest=&quot;manifest.php&quot;&gt;</pre>
<p>Het cache manifest maken (manifest.php):</p>
<pre class="brush: xml; title: ; notranslate">
CACHE MANIFEST
index.php
</pre>
<p>En klaar! De pagina is nu offline beschikbaar (mits deze al eenmalig bezocht is). Nadeel nu is dat wanneer de pagina (of data.txt veranderd), laten we zeggen dat er een input veld bij komt, wordt dit niet zichtbaar omdat de pagina altijd vanuit de cache geladen wordt. Wanneer wordt de pagina opnieuw opgehaald? Enkel als het manifest bestand veranderd. Dus zorgen we ervoor dat het manifest bestand veranderd als index.php en data.txt veranderen door bijvoorbeeld een md5 hash van de bestanden te maken, zodra de index.php of data.txt veranderd zal die hash ook veranderen. Laten we er een stukje commentaar in zetten met die hash.</p>
<pre class="brush: php; title: ; notranslate">
CACHE MANIFEST
index.php
# data.txt md5 hash: &lt;?=md5_file('data.txt');?&gt;
# index.php md5 hash: &lt;?=md5_file('index.php');?&gt;
</pre>
<h2>Localstorage als cache</h2>
<p>Top! Probleem opgelost! Maar als we het formulier &#8220;submitten&#8221; wanneer offline zal er niet veel gebeuren. Wat zijn de mogelijkheden om data tijdelijk bij de bezoeker op te slaan? Cookies! Prachtig maar veel gegevens kunnen we er niet in kwijt. <a href="http://www.w3.org/TR/webdatabase/">WebSQL</a>, wordt beperkt ondersteund en zoals bij W3C te lezen niet meer door ontwikkeld. <a href="http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html">IndexedDB</a>, helaas ook beperkt ondersteund. Houden we <a href="http://www.w3.org/TR/webstorage/">local storage</a> over! Wordt zelfs ondersteund door Internet Explorer (8+)! En&#8230; de code in! Laten we voor het gemak jQuery erbij pakken en eerst de form submit (wanneer offline) afvangen en de gegevens in localstorage stoppen:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;script type=&quot;text/javascript&quot; src=&quot;http://code.jquery.com/jquery-1.8.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
	//Naamloze functie maken
	(function()
	{
		//Form gesubmit?
		$('form').submit(function()
		{
			//Offline?
			if( ! navigator.onLine )
			{
				//De bezoeker vertellen wat er gebeurd
				alert('Je bent niet verbonden met het internet, de gegevens worden tijdelijk lokaal opgeslagen tot je weer verbonden bent met het internet.')

				//Nieuw item met alle ingevoerde gegevens uit het form aan localstorage toevoegen
				localStorage.setItem(new Date().getTime(), $(this).serialize() );

				//Alle ingevoerde velden leeg maken
				$('input[type=text]').val('');

				//Zorgen dat het form niet echt gesubmit wordt
				return false;
			}
		});

	//Naamloze functie direct uitvoeren
	})();
&lt;/script&gt;
</pre>
<p>Vervolgens moeten we ervoor zorgen dat wanneer er iets in localstorage zit dit de volgende keer verzonden wordt. Gezien dit allemaal javascript is en we dit middels ajax gaan doen eerst het &#8220;ajax afhandel script&#8221; maken, save.php:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
if($_POST){
	//Index echo'en zodat we deze kunnen verwijderen uit localstorage
	echo $_POST['index'];
	unset($_POST['index']);
	file_put_contents('data.txt', implode(', ',$_POST).&quot;\n&quot;, FILE_APPEND);
}
?&gt;
</pre>
<p>En weer door met javascript:</p>
<pre class="brush: jscript; title: ; notranslate">
//Online?
if( navigator.onLine )
{
	//Zijn er items in localstorage?
	if(localStorage.length)
	{
		//Door alle items in localstorage &quot;loopen&quot;
		for(var i in localStorage)
		{
			//Item versturen naar save.php
			$.ajax({
				url: 'save.php',
				data: 'index=' + i + '&amp;' + localStorage.getItem(i),
				type: 'POST',
				success: function(data){
					//Wanneer succesvol verzonden verwijderen uit localstorage
					localStorage.removeItem(data);
				}
			});
		}
	}
}
</pre>
<p>En klaar! Maar zoals je wellicht gemerkt hebt dien je eerst de pagina twee maal opnieuw te laten voordat de cache overschreven wordt. Om dit probleem op te lossen een kleine &#8220;hotfix&#8221; of &#8220;hack&#8221; om het zo maar te noemen:</p>
<pre class="brush: jscript; title: ; notranslate">
//Manifest bestand veranderd? (en dus index.php of data.txt)
window.applicationCache.addEventListener('updateready', function(e)
{
	if (window.applicationCache.status == window.applicationCache.UPDATEREADY)
	{
		//Cash verwijderen en nieuwe items laden
		window.applicationCache.swapCache();

		//Pagina opnieuw laden
		window.location.reload();
	}
}, false);
</pre>
<p>Best leuk dit! Waar kan je dit toepassen? Het is erg handig voor mobiele websites, komt wel eens voor dat de bezoeker geen internet heeft of dat het internet langzaam is (hopen dat het straks met 4G sneller gaat). Dan is het wel zo makkelijk dat de website bezocht kan worden én de ingevoerde gegevens verwerkt worden!</p>
<p><a class="demo-button" href="https://royduineveld.nl/demos/website-offline/" target="_blank">Klik hier voor een online demo</a></p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/website-offline-beschikbaar-maken-met-een-submit-fallback/">Website offline beschikbaar maken met een submit fallback</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://royduineveld.nl/website-offline-beschikbaar-maken-met-een-submit-fallback/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Alles nieuw!</title>
		<link>https://royduineveld.nl/alles-nieuw/</link>
		<comments>https://royduineveld.nl/alles-nieuw/#respond</comments>
		<pubDate>Thu, 15 Nov 2012 13:28:39 +0000</pubDate>
		<dc:creator><![CDATA[Roy Duineveld]]></dc:creator>
				<category><![CDATA[Tips & Trucs]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">https://royduineveld.nl/?p=16</guid>
		<description><![CDATA[<p>Mijn vorige website was wat verouderd zodoende een nieuwe! Eerste keer dat ik gebruik maak van impress.js maar ik ben over het resultaat te spreken! Onderweg naar het resultaat ook...</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/alles-nieuw/">Alles nieuw!</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Mijn vorige website was wat verouderd zodoende een nieuwe! Eerste keer dat ik gebruik maak van <a href="https://github.com/bartaz/impress.js" target="_blank">impress.js</a> maar ik ben over het resultaat te spreken! Onderweg naar het resultaat ook een alternatief tegen gekomen, gebaseerd op jQuery: <a href="https://github.com/shama/jmpress.js" target="_blank">jmpress.js</a>. Ook deze blog begonnen welke zich hopelijk snel vult!</p>
<p>Het bericht <a rel="nofollow" href="https://royduineveld.nl/alles-nieuw/">Alles nieuw!</a> verscheen eerst op <a rel="nofollow" href="https://royduineveld.nl">Roy Duineveld</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://royduineveld.nl/alles-nieuw/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>