Avatar billede mortency Nybegynder
04. januar 2005 - 11:20 Der er 5 kommentarer og
1 løsning

To afhængige selects, feil ved validering husker ikke input

Hei jeg har to afhængige selects.

Med denne så kan man velge bilmerke så --> modell under det spesifike merket.

Problemet er at når feltene blir sendt for validering og noen av feltene er feil utfyllt så huskes ikke feltene i de afhængige selects. Noen som har noen forslag, eller løsning på dette problemet?

**************
Litt kode:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
  <script language=Javascript src="optionex.js"></script>
  <script language=Javascript>
  var oFabrikat = new OptionCollection();
  oFabrikat.Add('249','(249) -106 ','27');oFabrikat.Add('478','(478) -116','3');oFabrikat.Add('452','(452) -150E23','46');oFabrikat.Add('454','(454) -190e27','46');oFabrikat.Add('280','(280) -2 serie','29');oFabrikat.Add('251','(251) -206','27');oFabrikat.Add('443','(443) -3 ','22');oFabrikat.Add('36','(36) -3 serie','3');oFabrikat.Add('254','(254) -307','27');oFabrikat.Add('152','(152) -323','22');oFabrikat.Add('446','(446) -35s12','46');oFabrikat.Add('447','(447) -35s15','46');oFabrikat.Add('319','(319) -4 - Runner','35');oFabrikat.Add('281','(281) -4 serie','29');oFabrikat.Add('257','(257) -406','27');oFabrikat.Add('455','(455) -413CD1','23');oFabrikat.Add('37','(37) -5 serie','3');oFabrikat.Add('448','(448) -50c13','46');oFabrikat.Add('153','(153) -6','22');oFabrikat.Add('282','(282) -6 serie','29');oFabrikat.Add('261','(261) -607','27');oFabrikat.Add('154','(154) -626','22');oFabrikat.Add('284','(284) -75','29');oFabrikat.Add('441','(441) -75 E 17','46');oFabrikat.Add('450','(450) -75e17p','46');oFabrikat.Add('263','(263) -807','27');oFabrikat.Add('453','(453) -80e21','46');oFabrikat.Add('456','(456) -817','23');oFabrikat.Add('457','(457) -818','23');oFabrikat.Add('449','(449) -85e21p','46');oFabrikat.Add('286','(286) -9-3','30');oFabrikat.Add('287','(287) -9-5','30');oFabrikat.Add('175','(175) -A - Klasse','23');oFabrikat.Add('17','(17) -A2','2');oFabrikat.Add('18','(18) -A3','2');oFabrikat.Add('19','(19) -A4','2');oFabrikat.Add('20','(20) -A6','2');oFabrikat.Add('103','(103) -Accent','16');oFabrikat.Add('91','(91) -Accord','15');oFabrikat.Add('229','(229) -Agila','26');oFabrikat.Add('292','(292) -Alhambra','31');oFabrikat.Add('212','(212) -Almera','25');oFabrikat.Add('309','(309) -Alto','34');oFabrikat.Add('293','(293) -Arosa','31');oFabrikat.Add('231','(231) -Astra','26');oFabrikat.Add('104','(104) -Atos','16');oFabrikat.Add('320','(320) -Avensis','35');oFabrikat.Add('156','(156) -B 2000','22');oFabrikat.Add('157','(157) -B 2200','22');oFabrikat.Add('158','(158) -B 2500','22');oFabrikat.Add('159','(159) -B 2600','22');oFabrikat.Add('310','(310) -Baleno','34');oFabrikat.Add('120','(120) -Beata','18');oFabrikat.Add('336','(336) -Beetle','36');oFabrikat.Add('383','(383) -Berlingo','8');oFabrikat.Add('338','(338) -Bora','36');oFabrikat.Add('264','(264) -Boxer','27');oFabrikat.Add('406','(406) -Brava','12');oFabrikat.Add('176','(176) -C - Klasse','23');oFabrikat.Add('465','(465) -C-MAX','13');oFabrikat.Add('444','(444) -C2','8');oFabrikat.Add('385','(385) -C3','8');oFabrikat.Add('386','(386) -C5','8');oFabrikat.Add('387','(387) -C8','8');oFabrikat.Add('23','(23) -Cabriolet','2');oFabrikat.Add('461','(461) -Cabstar','25');oFabrikat.Add('339','(339) -Caddy','36');oFabrikat.Add('321','(321) -Camry','35');oFabrikat.Add('463','(463) -Canter','24');oFabrikat.Add('340','(340) -Caravelle','36');oFabrikat.Add('464','(464) -Carens','18');oFabrikat.Add('322','(322) -Carina','35');oFabrikat.Add('186','(186) -Carisma','24');oFabrikat.Add('121','(121) -Carnival','18');oFabrikat.Add('93','(93) -Civic','15');oFabrikat.Add('122','(122) -Clarus','18');oFabrikat.Add('269','(269) -Clio','28');oFabrikat.Add('187','(187) -Colt','24');oFabrikat.Add('233','(233) -Combo','26');oFabrikat.Add('424','(424) -Cooper','42');oFabrikat.Add('294','(294) -Cordoba','31');oFabrikat.Add('323','(323) -Corolla','35');oFabrikat.Add('234','(234) -Corsa','26');oFabrikat.Add('188','(188) -Cosmos','24');oFabrikat.Add('105','(105) -Coupe','16');oFabrikat.Add('64','(64) -Courier','13');oFabrikat.Add('94','(94) -CR-V','15');oFabrikat.Add('123','(123) -Credos','18');oFabrikat.Add('95','(95) -CRX','15');oFabrikat.Add('437','(437) -Daily 35 S','46');oFabrikat.Add('438','(438) -Daily 50 C 13','46');oFabrikat.Add('475','(475) -Daily 65c15','46');oFabrikat.Add('160','(160) -Demio','22');oFabrikat.Add('148','(148) -Discovery','21');oFabrikat.Add('466','(466) -Ducato','12');oFabrikat.Add('178','(178) -E - Klasse','23');oFabrikat.Add('161','(161) -E 2000','22');oFabrikat.Add('162','(162) -E 2200','22');oFabrikat.Add('66','(66) -E-250','13');oFabrikat.Add('189','(189) -Eclipse','24');oFabrikat.Add('68','(68) -Econovan','13');oFabrikat.Add('106','(106) -Elantra','16');oFabrikat.Add('270','(270) -Espace','28');oFabrikat.Add('439','(439) -Euro Cargo 85 E18','46');oFabrikat.Add('440','(440) -Euro Cargo 85 E21','46');oFabrikat.Add('70','(70) -Excursion','13');oFabrikat.Add('265','(265) -Expert','27');oFabrikat.Add('271','(271) -Express','28');oFabrikat.Add('72','(72) -F-250','13');oFabrikat.Add('299','(299) -Fabia','32');oFabrikat.Add('301','(301) -Felicia','32');oFabrikat.Add('73','(73) -Fiesta','13');oFabrikat.Add('74','(74) -Focus','13');oFabrikat.Add('304','(304) -Forester','33');oFabrikat.Add('149','(149) -Freelander','21');oFabrikat.Add('235','(235) -Frontera','26');oFabrikat.Add('451','(451) -Fusion','13');oFabrikat.Add('190','(190) -Galant','24');oFabrikat.Add('75','(75) -Galaxy','13');oFabrikat.Add('191','(191) -Galloper','24');oFabrikat.Add('107','(107) -Getz','16');oFabrikat.Add('343','(343) -Golf','36');oFabrikat.Add('311','(311) -Grand Vitara','34');oFabrikat.Add('376','(376) -Grand Voyager','7');oFabrikat.Add('108','(108) -H-1','16');oFabrikat.Add('476','(476) -H2','48');oFabrikat.Add('325','(325) -HiAce','35');oFabrikat.Add('326','(326) -HiClass','35');oFabrikat.Add('327','(327) -HiLux','35');oFabrikat.Add('96','(96) -HR-V','15');oFabrikat.Add('295','(295) -Ibiza','31');oFabrikat.Add('312','(312) -Ignis','34');oFabrikat.Add('305','(305) -Impreza','33');oFabrikat.Add('296','(296) -Inca','31');oFabrikat.Add('458','(458) -Interstar','25');oFabrikat.Add('422','(422) -IS 200','40');oFabrikat.Add('266','(266) -J5','27');oFabrikat.Add('97','(97) -Jazz','15');oFabrikat.Add('313','(313) -Jimny','34');oFabrikat.Add('389','(389) -Jumper','8');oFabrikat.Add('306','(306) -Justy','33');oFabrikat.Add('77','(77) -KA','13');oFabrikat.Add('272','(272) -Kangoo','28');oFabrikat.Add('215','(215) -King Cab','25');oFabrikat.Add('217','(217) -King Van','25');oFabrikat.Add('395','(395) -Korando','9');oFabrikat.Add('462','(462) -Kubistar','25');oFabrikat.Add('192','(192) -L 200','24');oFabrikat.Add('193','(193) -L 300','24');oFabrikat.Add('194','(194) -L 400','24');oFabrikat.Add('273','(273) -Laguna','28');oFabrikat.Add('195','(195) -Lancer','24');oFabrikat.Add('328','(328) -Landcrusier','35');oFabrikat.Add('307','(307) -Legacy','33');oFabrikat.Add('297','(297) -Leon','31');oFabrikat.Add('314','(314) -Liana','34');oFabrikat.Add('427','(427) -LT 35','36');oFabrikat.Add('79','(79) -LTD','13');oFabrikat.Add('124','(124) -Magentis','18');oFabrikat.Add('467','(467) -Mascott','28');oFabrikat.Add('274','(274) -Master','28');oFabrikat.Add('397','(397) -Matiz','9');oFabrikat.Add('110','(110) -Matrix','16');oFabrikat.Add('219','(219) -Maxima','25');oFabrikat.Add('275','(275) -Megane','28');oFabrikat.Add('469','(469) -Meriva','26');oFabrikat.Add('220','(220) -Micra','25');oFabrikat.Add('468','(468) -Midlum','28');oFabrikat.Add('460','(460) -MK','25');oFabrikat.Add('80','(80) -Mondeo','13');oFabrikat.Add('196','(196) -Montero','24');oFabrikat.Add('239','(239) -Movano','26');oFabrikat.Add('163','(163) -MPV','22');oFabrikat.Add('378','(378) -Neon','7');oFabrikat.Add('302','(302) -Octavia','32');oFabrikat.Add('240','(240) -Omega','26');oFabrikat.Add('436','(436) -One','42');oFabrikat.Add('308','(308) -Outback','33');oFabrikat.Add('197','(197) -Pajero','24');oFabrikat.Add('198','(198) -Pajero Pinin','24');oFabrikat.Add('199','(199) -Pajero Sport','24');oFabrikat.Add('267','(267) -Partner','27');oFabrikat.Add('346','(346) -Passat','36');oFabrikat.Add('221','(221) -Patrol','25');oFabrikat.Add('83','(83) -Pick up','13');oFabrikat.Add('330','(330) -Picnic','35');oFabrikat.Add('347','(347) -Polo','36');oFabrikat.Add('125','(125) -Pregio','18');oFabrikat.Add('167','(167) -Premacy','22');oFabrikat.Add('331','(331) -Previa','35');oFabrikat.Add('126','(126) -Pride','18');oFabrikat.Add('223','(223) -Primera','25');oFabrikat.Add('85','(85) -Puma','13');oFabrikat.Add('428','(428) -Punto 80','12');oFabrikat.Add('150','(150) -Range Rover','21');oFabrikat.Add('332','(332) -RAV4','35');oFabrikat.Add('474','(474) -Rexton','47');oFabrikat.Add('127','(127) -Rio','18');oFabrikat.Add('366','(366) -S40','37');oFabrikat.Add('367','(367) -S60','37');oFabrikat.Add('369','(369) -S80','37');oFabrikat.Add('112','(112) -Santa Fe','16');oFabrikat.Add('200','(200) -Santamo','24');oFabrikat.Add('203','(203) -Sapce Runner','24');oFabrikat.Add('201','(201) -Sapporo','24');oFabrikat.Add('390','(390) -Saxo','8');oFabrikat.Add('276','(276) -Scenic','28');oFabrikat.Add('380','(380) -Sebring','7');oFabrikat.Add('128','(128) -Sephia','18');oFabrikat.Add('350','(350) -Sharan','36');oFabrikat.Add('129','(129) -Shuma','18');oFabrikat.Add('202','(202) -Sigma','24');oFabrikat.Add('470','(470) -Signum','26');oFabrikat.Add('243','(243) -Sintra','26');oFabrikat.Add('113','(113) -Sonata','16');oFabrikat.Add('130','(130) -Sorento','18');oFabrikat.Add('204','(204) -Space Star','24');oFabrikat.Add('205','(205) -Space Wagon','24');oFabrikat.Add('131','(131) -Sportage','18');oFabrikat.Add('426','(426) -Sprinter','23');oFabrikat.Add('473','(473) -Starcraft','6');oFabrikat.Add('114','(114) -Starex','16');oFabrikat.Add('206','(206) -Starion','24');oFabrikat.Add('429','(429) -Stilo','12');oFabrikat.Add('207','(207) -Strada','24');oFabrikat.Add('303','(303) -Superb','32');oFabrikat.Add('425','(425) -Tahoe','6');oFabrikat.Add('477','(477) -Terano','25');oFabrikat.Add('433','(433) -Terracan','16');oFabrikat.Add('245','(245) -Tigra','26');oFabrikat.Add('298','(298) -Toledo','31');oFabrikat.Add('471','(471) -Touran','36');oFabrikat.Add('278','(278) -Traffic','28');oFabrikat.Add('89','(89) -Transit','13');oFabrikat.Add('420','(420) -Transporter','36');oFabrikat.Add('279','(279) -Twingo','28');oFabrikat.Add('432','(432) -V40','37');oFabrikat.Add('445','(445) -V50','37');oFabrikat.Add('372','(372) -V70','37');oFabrikat.Add('185','(185) -Vaneo','23');oFabrikat.Add('246','(246) -Vectra','26');oFabrikat.Add('184','(184) -Vito','23');oFabrikat.Add('247','(247) -Vivaro','26');oFabrikat.Add('316','(316) -Wagon R+','34');oFabrikat.Add('228','(228) -X -Trail','25');oFabrikat.Add('442','(442) -X3','3');oFabrikat.Add('391','(391) -Xantia','8');oFabrikat.Add('472','(472) -XC70','37');oFabrikat.Add('171','(171) -Xedos 6','22');oFabrikat.Add('393','(393) -Xsara','8');oFabrikat.Add('335','(335) -Yaris','35');oFabrikat.Add('402','(402) -YRV','10');oFabrikat.Add('248','(248) -Zafira','26');

  function displayWindow(url, width, height) {
          var Win = window.open(url,"displayWindow",'width=' + width + ',height=' + height + ',resizable=0,scrollbars=no,menubar=no,status=yes' );
  } 
  </script>
</head>
<body bgcolor="#FFFFFF" text="#000000" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<table width="100%" border="0" cellspacing="0" cellpadding="0" height="100%">

                     
<table width="595" border="0" cellspacing="0" cellpadding="1">
<form action="admin.asp?mode=addcar&action=add" method="post" name="formaddcar">
  <tr>
    <td width="150" class="headingtable">Fabrikat:</td>
    <td class="headingtable">
       
        <SELECT name="txtFabrikat" onchange="UpdateSelect('txtModell','formaddcar',this.options[this.selectedIndex].value,oFabrikat);" class="formselect">
        <option value="">[ Velg fabrikat ]</option>         
       
        <option value="2">(2) - Audi</option>   
       
        <option value="3">(3) - BMW</option>   
       
        <option value="6">(6) - Chevrolet</option>   
       
        <option value="7">(7) - Chrysler</option>   
       
        <option value="8">(8) - Citroen</option>   
       
        <option value="9">(9) - Daewoo</option>   
       
        <option value="10">(10) - Daihatsu</option>   
       
        <option value="12">(12) - Fiat</option>   
       
        <option value="13">(13) - Ford</option>   
       
        <option value="15">(15) - Honda</option>   
       
        <option value="48">(48) - Hummer</option>   
       
        <option value="16">(16) - Hyundai</option>   
       
        <option value="46">(46) - Iveco</option>   
       
        <option value="18">(18) - Kia</option>   
       
        <option value="21">(21) - Land Rover</option>   
       
        <option value="40">(40) - Lexus</option>   
       
        <option value="22">(22) - Mazda</option>   
       
        <option value="23">(23) - Mercedes</option>   
       
        <option value="42">(42) - Mini</option>   
       
        <option value="24">(24) - Mitsubishi</option>   
       
        <option value="25">(25) - Nissan</option>   
       
        <option value="26">(26) - Opel</option>   
       
        <option value="27">(27) - Peugeot</option>   
       
        <option value="28">(28) - Renault</option>   
       
        <option value="29">(29) - Rover</option>   
       
        <option value="30">(30) - Saab</option>   
       
        <option value="31">(31) - Seat</option>   
       
        <option value="32">(32) - Skoda</option>   
       
        <option value="47">(47) - SsangYong</option>   
       
        <option value="33">(33) - Subaru</option>   
       
        <option value="34">(34) - Suzuki</option>   
       
        <option value="35">(35) - Toyota</option>   
       
        <option value="36">(36) - Volkswagen</option>   
       
        <option value="37">(37) - Volvo</option>   
       
        </select> 
    </td>
  </tr>
  <tr bgcolor="#CCCCCC">
    <td width="150" class="headingtable">Modell.</td>
    <td class="headingtable">
        <select name="txtModell" id="txtModell" onchange="UpdateSelect('carcolors','formaddcar',this.options[this.selectedIndex].value);" class="formselect">
          <option>[ Velg modell ]</option>
          <option></option>
          <option></option>
          <option></option>
        </select> 
    </td>
  </tr>
</form> 
</table>
</body>
</html>
Avatar billede roenving Novice
05. januar 2005 - 17:18 #1
Det er jo ikke muligt at vide, når du ikke viser eller linker til den kode, som aktuelt udfylder den anden select (optionex.js !-)
Avatar billede mortency Nybegynder
06. januar 2005 - 11:07 #2
//Roenving

Sånn ser optionex.js ut:

var NS4 = (document.layers)?true:false;
var IE4 = (document.all)?true:false;
   
function _struct(child,childcaption,parent){
this.child = child;
this.childcaption = childcaption;
this.parent    = parent;
}
function _addobject(child,childcaption,parent){
var obj = new _struct();
obj.child = child;
obj.childcaption = childcaption;
obj.parent = parent;
return(obj);
}
function insertEntry(child,childcaption,parent){
    if(child.length > 0 ){       
        for(var i=0;i<this.length;i++)
            if(this.items[i].child == child)
                return;           
        this.items[this.length++] = _addobject(child,childcaption,parent);       
    }
}
function OptionCollection(){
this.length=0;
this.items = new Object();
this.Add=insertEntry
}

function clearSelect(oSelect){
var iCount=0;
if(!oSelect) return;
iCount = oSelect.options.length;
for(var i=0;i<iCount;i++){
    if(IE4)
        oSelect.options.remove(0);
    else if(NS4)
        oSelect.options[0]=null;
}
}
function addOptions(oSelect,olist,parent){
    var elOption;
    var idxSelect=0;   

    //check arguments.
    if((!olist) || (!oSelect))return;       
    if(parent.length <=    0)     return;
                   
    //now looop through all the list items only entering relevant options.
    clearSelect(oSelect);   
   
    //add a blank list
    elBlankOption = new Option();
    elBlankOption.text = "";
    if(NS4) oSelect.options[0] = elBlankOption
    else if(IE4) oSelect.options.add(elBlankOption,0)
   
    elBlankOption.value = "";
    for(var i=0;i<olist.length;i++){       
        //only the child entries of the parent               
        if(olist.items[i].parent == parent){                                   
            elOption = new Option();
            //now IE and NS have a different way to handle object creation.
            if(NS4){                       
                elOption.value = olist.items[i].child
                elOption.text = olist.items[i].childcaption
                oSelect.options[idxSelect] = elOption               
            }else if(IE4){               
                elOption.value = olist.items[i].child
                elOption.text = olist.items[i].childcaption
                oSelect.options.add(elOption,idxSelect)                   
            }                       
            idxSelect++;
            delete(elOption);
        }           
    }   
}

function clearOptions(szSelect,szForm){
if(szSelect.length <= 0 || szForm.length <=0)
    alert("error:clearOption must pass arguments");   
if(IE4)
clearSelect(document.all.item(szSelect));
else if(NS4)
clearSelect(eval('document.' + szForm + '.' + szSelect));
}

function listAllOptions(szSelect,szForm,olist){
    var elOption;
    var idxSelect=0;
    var oSelect = new Object();
           
    //check arguments.
    if(!olist)return;           
   
    if(IE4)
        oSelect = document.all.item(szSelect);
    else if(NS4)
        oSelect = eval('document.' + szForm + '.' + szSelect);
   
    if(!oSelect)return;           
                       
    //now looop through all the list items entering all
    clearSelect(oSelect);
    for(var i=0;i<olist.length;i++){                           
        elOption = new Option();
        //now IE and NS have a different way to handle object creation.
        if(NS4){                       
            elOption.value = olist.items[i].child
            elOption.text = olist.items[i].childcaption
            oSelect.options[idxSelect] = elOption               
        }else if(IE4){               
            elOption.value = olist.items[i].child
            elOption.text = olist.items[i].childcaption
            oSelect.options.add(elOption,idxSelect)                   
        }                       
        idxSelect++;
        delete(elOption);                   
    }   
}

function UpdateSelect(szSelect,szForm,szParent,olist){
if(IE4)
addOptions(document.all.item(szSelect),olist,szParent);
else if(NS4)
addOptions(eval('document.' + szForm + '.' + szSelect),olist,szParent);
}
Avatar billede roenving Novice
08. januar 2005 - 09:37 #3
Du har ikke været så heldig, da du har fundet et forældet script fra browser-krigens dage, hvor det var nødvendigt at tage højde for de to meget forskellige browsere IE4 og NS4, men idag understøtter scriptet stadig kun de nævnte plus senere udgaver af IE ...

Du skal derfor mindst have fat i en opdateret udgave af scriptet, som understøtter almindelig DOM-binding anno 1998 !-)

Derudover har du et tilfælde af ulovlig nesting, men det er nu hurtigt klaret, for du skal bare ombytte form- og table-tagget både ved åbning og lukning:

<form action="admin.asp?mode=addcar&action=add" method="post" name="formaddcar">
<table width="595" border="0" cellspacing="0" cellpadding="1">

...

</table>
</form>

-- så til dit spørgsmål, som jeg åbenbart ikke gennemskuede i første omgang, da jeg troede, det var relateret til måden selectene blev oprettet, men det er det åbenlyst ikke, så det handler simpelthen om, at du foretager din validering server-side, og der ikke opretter selects igen, for ved afsendelse af formen, vil den blive afsendt fra serveren i sin oprindelige form, medmindre du server-side opretter selects i en passende sammensætning !o]

-- du kan klare problemet ved at lave en client-side validering i javascript, hvor du simpelthen tester om der er valgt i den første select (samt tester om andre vigtige felter er udfyldt !-)

<form action="admin.asp?mode=addcar&action=add" method="post" name="formaddcar" onsubmit="return valider(this);">

<script type="text/javascript">
function valider(f){
  if(f.txtFabrikat.selectedIndex==0){
    alert('Du mangler at vælge bilfabrikat');
    f.txtFabrikat.focus();
    return false;
  }
  //andre felter, f.eks.
  if(f.navn.value=""){
    alert('Du mangler at udfylde dit navn');
    f.navn.focus();
    return false;
  }
  return true;
}
</script>

-- på den måde vil formen kun afsendes, hvis alle valideringer holder, og scriptet når ned til den afsluttende return true; !-)
Avatar billede mortency Nybegynder
06. april 2005 - 16:03 #4
Post et svar
Avatar billede roenving Novice
07. april 2005 - 15:10 #5
Velbekomme '-)
Avatar billede roenving Novice
22. juni 2005 - 16:03 #6
-- og tak for point ;~}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester