Toon posts:

[ASP.net / C#] - Verlaten record -> wijzigingen opslaan

Pagina: 1
Acties:

Verwijderd

Topicstarter
Mijn probleem: Ik heb een table met records, als op een record wordt geklikt worden de details getoond. Hier kan de gebruiker het record wijzigen. Tevens kan hij naar het eerste, vorige, volgende of laatste record, dit werkt ook:

code:
1
2
3
4
5
6
7
8
9
10
11
try 
{
    DataRow[] drc = table.Select("Issue_nr = '"+issueID+"'");
    DataRow dr = drc[0];
    string recID = dr["rec_id"].ToString();
    Response.Redirect("IssueDetail.aspx?issueID="+issueID+"&recID="+recID);
}
catch
{
    ShowMessage("Er is geen vorig issue gevonden!");
}

Nu wil ik eigenlijk dat de gebruiker wordt gevraagd of hij de wijzigingen op wil slaan. Het probleem is dat het windowresult (yes of no) alleen clientside in jscript bekend is, logisch. Ik heb gegoogled en kwam hier uit. Prima site, maar daar wordt alleen het window getoond en niets opgeslagen.

Ik had reeds de volgende jscriptcode gemaakt:

code:
1
2
3
4
5
6
var WinSettings ="dialogWidth:250px;dialogHeight:250px;,status=yes,toolbar=no,menubar=no,location=no"
arg=window.showModalDialog("ModalForm.aspx", null, WinSettings)"
if (arg==\"Yes\")
{
window.location=\"IssueDetail.aspx?issueID="+Session["IssueID"].ToString()+"&recID="+Session["RecID"].ToString()+"&SaveChanges=true\"";
}

Dit kan ik wel laten toevoegen aan de client jscript code met registerstartupscript, maar het probleem is dat dan Response.Redirect niet moet worden aangeroepen.

Aangezien sommigen wel weten dat ik iets te snel loop te kloten, vraag ik nu alvast jullie help, voordat mijn code weer een chaos wordt :). Oplossing die ik in gedachten had is om de response.redirect weg te halen en bij de else-tak in de jscript code de code neer te zetten om naar het vorige / volgende / ... / record te gaan.

Dit wordt echter geen mooie oplossing. Als de gebruiker dan op vorige klikt en wil opslaan, zal het window gerefresht worden op het huidge window en zal het record worden opgeslagen. Echter, dan zal ik weer servercode moeten schrijven die het window opnieuw refresht en naar het vorige/volgende /.. record gaat.

[ Voor 8% gewijzigd door Verwijderd op 07-10-2005 10:28 ]


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik weet niet precies hoe je het nu hebt gedaan en waarom je geen Response.Redirect wil gebruiken.

Maar ik zie hier dat je de location wil veranderen met javascript. Als de gebruiker de gegevens niet op wil slaan is dat niet zo erg.

Maar ik zou het eerder doen dat je next/prev button ( LinkButton kan ook natuurlijk ) via javascript een form laat zien wat de gebruiker wil en het resultaat in een Hidden field zet. Je kan dan gewoon een postback uit laten voeren en daar de gegevens opslaan. Daarna kan je gewoon een redirect doen.

In het geval dat de gebruiker de gegevens niet op wil slaan kan je altijd nog besluiten direct met javascript te redirecten.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Verwijderd

Ik zou gewoon hetvolgende doen:

code:
1
2
myButton.Attributes.Add("onclick", 
"return(confirm('Weet u zeker dat u dit item wilt opslaan?'));");


De click van de button gaat dan alleen bij een [ja] af. Dus in code behind kun je bij het click-event gewoon opslaan.

[ Voor 36% gewijzigd door Verwijderd op 07-10-2005 12:20 ]


Verwijderd

Topicstarter
rwb schreef op vrijdag 07 oktober 2005 @ 12:10:
Ik weet niet precies hoe je het nu hebt gedaan en waarom je geen Response.Redirect wil gebruiken.

Maar ik zie hier dat je de location wil veranderen met javascript. Als de gebruiker de gegevens niet op wil slaan is dat niet zo erg.
De eerste code die ik heb gepost, zorgt ervoor dat het eerste record wordt getoond. De oude gegevens zijn dan weg, daarom moeten eerst de gegevens worden opgeslagen en vervolgens een redirect naar het eerste record worden uitgevoerd. Dat bedoelde ik ermee dat de redirect niet moet worden uitgevoerd, beetje slecht uitgelegd... Er moet altijd geredirect worden naar het eerste/laatste/vorige/volgende record, ongeacht of er opgeslagen moet worden of niet.
Maar ik zou het eerder doen dat je next/prev button ( LinkButton kan ook natuurlijk ) via javascript een form laat zien wat de gebruiker wil en het resultaat in een Hidden field zet. Je kan dan gewoon een postback uit laten voeren en daar de gegevens opslaan. Daarna kan je gewoon een redirect doen.

In het geval dat de gebruiker de gegevens niet op wil slaan kan je altijd nog besluiten direct met javascript te redirecten.
Hoe haal ik dan serverside de waarde uit het hidden field?? Daar heb ik geen ervaring mee. Iets in de trend van <input type=hidden id=Save runat=server>??
Verwijderd schreef op vrijdag 07 oktober 2005 @ 12:19:
Ik zou gewoon hetvolgende doen:

code:
1
2
myButton.Attributes.Add("onclick", 
"return(confirm('Weet u zeker dat u dit item wilt opslaan?'));");


De click van de button gaat dan alleen bij een [ja] af. Dus in code behind kun je bij het click-event gewoon opslaan.
Dit is volgens mij niet helemaal wat ik bedoel... Het onclick-event moet sowieso worden aangeroepen, er moet namelijk geredirect worden naar het eerste/../../.. record. En met jou oplossing zou ik 2 onclickevents moeten hebben. Dit lijkt wel de oplossing, maar volgens mij is het niet mogelijk met wat ik zoek.

[ Voor 21% gewijzigd door Verwijderd op 07-10-2005 12:28 ]


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op vrijdag 07 oktober 2005 @ 12:25:
[...]
Hoe haal ik dan serverside de waarde uit het hidden field?? Daar heb ik geen ervaring mee. Iets in de trend van <input type=hidden id=Save runat=server>??
Ja zoiets idd. Je kan ook alle standaard HtmlControl als servercontrol laten draaien. Je krijgt dan in je CodeBehind iets als een HtmlInputHidden control en kan je gewoon op dezelfde manier gebruiken als je met je asp.net controls doet.
Verwijderd schreef op vrijdag 07 oktober 2005 @ 12:19:
Ik zou gewoon hetvolgende doen:

code:
1
2
myButton.Attributes.Add("onclick", 
"return(confirm('Weet u zeker dat u dit item wilt opslaan?'));");


De click van de button gaat dan alleen bij een [ja] af. Dus in code behind kun je bij het click-event gewoon opslaan.
Dat werkt alleen als je zowiezo niet terug naar de server hoeft.

[ Voor 32% gewijzigd door Woy op 07-10-2005 13:15 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Verwijderd

Topicstarter
@rwb: Ik heb nu het volgende en volgens mij zou het moeten werken...

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script languange=javascript type=text/javascript> 
var WinSettings = ... // niet interessant
 arg=window.showModalDialog("ModalForm.aspx", null, WinSettings)
if (arg=="Yes") 
{
    document.getElementById('_saveIssue').value="true"
    document.getElementById('_recIDToLoad').value="_1MI0LLPGJ"
    document.getElementById('_issueIDToLoad').value="1"
}
else
{
    document.getElementById('_saveIssue').value="false"
}
Form1.submit()
</script>

(Dit is het script dat voor 1 bepaald record is gegenereerd, vandaar dat de recID en issueID al in zijn gevuld).
De velden heb ik zo gedefinieerd:

HTML:
1
2
3
<input id="_saveIssue" type="hidden" runat="server"> 
<input id="_issueIDToLoad" type="hidden" name="_issueToLoad" runat="server">
<input id="_recIDToLoad" type="hidden" name="_recIDToLoad" runat="server">

Ik kreeg in het begin een foutmelding dat de velden niet gevonden konden worden, toen ben ik erachter gekomen dat het dus met document.getElementById moest.

In de codebehind staat die in de Page_Load

C++:
1
2
3
4
5
if (Request.Form["_saveIssue"] == "true") 
{
    this.SaveIssue();
this.Response.Redirect("IssueDetail.aspx?issueID="+Request.Form["_issueIDToLoad"]+"&recID="+Request.Form["_recIDToLoad"]);
}

Maar, hij komt nooit in de then-tak... Wat doe ik hier fout? Het venster wordt getoond, nadat op Ja wordt geklikt wordt het popupvenster gesloten en wordt het detailscherm herladen (Page_Load wordt aangeroepen).

offtopic:
De code is geen c++, maar c#, maar die staat niet bij de UBB-codes :)


/Edit: Ik heb nu voor het if-statement een breakpoint geset (de if van de code behind dus). Het blijkt dus dat het dus niet goed gaat, eerst wordt de breakpoint bereikt en vervolgens wordt het popupvenster getoond... Logisch ook... Moet ik nog even zorgen dat na het klikken op Ja of Nee er een postback wordt veroorzaakt. Wordt vervolgd :)

/Edit: de regel in de js Form1.submit() toegevoegd, het werkt nu wel. Op deze manier heb ik wel 3 postbacks:

1) Popup tonen
2) Checken of huidige record opgeslagen moet worden
3) Volgende record tonen.

Punt 2 en 3 kunnen misschien wel in 1 keer, maar dan klopt de adresbalk niet meer en zal bij een refresh het oude record weer getoond worden...

[ Voor 48% gewijzigd door Verwijderd op 07-10-2005 14:12 ]


  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
ik heb ook zoiets gemaakt.

Een extra ding wat ik erbij heb is een speciale javascript variabele die bijhoudt OF er wel iets is gewijzigd op het scherm. Als er namelijk niks is gewijzigd, hoef je het ook niet te vragen.

Omdat je soms in de code-behind is hebt gewijzigd wat nog niet is opgeslagen, heb ik een control gemaakt die je serverside kan instellen of er wijzigingen zijn. Deze print alleen een javascript variabele of er al wijzigingen zijn. Ook bij postbacks onthoudt ie het in de viewstate.

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op vrijdag 07 oktober 2005 @ 13:56:
@rwb: Ik heb nu het volgende en volgens mij zou het moeten werken...

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script languange=javascript type=text/javascript> 
var WinSettings = ... // niet interessant
 arg=window.showModalDialog("ModalForm.aspx", null, WinSettings)
if (arg=="Yes") 
{
    document.getElementById('_saveIssue').value="true"
    document.getElementById('_recIDToLoad').value="_1MI0LLPGJ"
    document.getElementById('_issueIDToLoad').value="1"
}
else
{
    document.getElementById('_saveIssue').value="false"
}
Form1.submit()
</script>
waarom maak je daar geen function van en roep je die aan in de onclick van je button
JavaScript:
1
2
3
4
function AskSave()
{
   //hier je code om te vragen of opgeslagen moet worden
}


en dan in je codebehind
C#:
1
btnNext.Attributes[ "onclick" ] = "AskSave();";
HTML:
1
2
3
<input id="_saveIssue" type="hidden" runat="server"> 
<input id="_issueIDToLoad" type="hidden" name="_issueToLoad" runat="server">
<input id="_recIDToLoad" type="hidden" name="_recIDToLoad" runat="server">
Kunnen die _issueIDToLoad en _recIDToLoad ook veranderd worden clientside? Anders kun je ze beter niet in een hidden field stoppen maar bijvoorbeeld in je ViewState of Session of iets dergelijks
in de codebehind staat die in de Page_Load
C#:
1
2
3
4
5
if (Request.Form["_saveIssue"] == "true") 
{
    this.SaveIssue();
this.Response.Redirect("IssueDetail.aspx?issueID="+Request.Form["_issueIDToLoad"]+"&recID="+Request.Form["_recIDToLoad"]);
}

Maar, hij komt nooit in de then-tak... Wat doe ik hier fout? Het venster wordt getoond, nadat op Ja wordt geklikt wordt het popupvenster gesloten en wordt het detailscherm herladen (Page_Load wordt aangeroepen).
Waarom doe je dat in de Page_Load en niet in de eventhandler van je button dus zo

C#:
1
2
3
4
5
6
7
8
9
BtnNext_Click( object sender, EventArgs e )
{
    //Hier niet uit je Request.Form halen maar gewoon je control aanspreken.
    //Anders heeft het ook geen nut om het control serverside te laten draaien
    if( _saveIssue.Value.Equals( "true" ) )
    {
        //doe je ding
    }
}
offtopic:
De code is geen c++, maar c#, maar die staat niet bij de UBB-codes :)
offtopic:
Die bestaat dus wel gewoon ;)
/Edit: de regel in de js Form1.submit() toegevoegd, het werkt nu wel. Op deze manier heb ik wel 3 postbacks:
Dat hoef je dus ook niet te doen als je die functie gewoon aanroept in je onclick

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Verwijderd

Topicstarter
joopst schreef op vrijdag 07 oktober 2005 @ 14:13:
ik heb ook zoiets gemaakt.

Een extra ding wat ik erbij heb is een speciale javascript variabele die bijhoudt OF er wel iets is gewijzigd op het scherm. Als er namelijk niks is gewijzigd, hoef je het ook niet te vragen.
Inderdaad, dit ga ik nog inbouwen. Ik wilde eerst het uberhaupt werkend krijgen om het te kunnen saven :).
Omdat je soms in de code-behind is iets (typo?) hebt gewijzigd wat nog niet is opgeslagen, heb ik een control gemaakt die je serverside kan instellen of er wijzigingen zijn. Deze print alleen een javascript variabele of er al wijzigingen zijn. Ook bij postbacks onthoudt ie het in de viewstate.
Hoe doe je dit precies?? Ik had zelf het idee om aan elk invoerveld een onchange-javascript te hangen die vervolgens een hidden variabele instelt. Je kunt toch niet serverside weten of er clientside iets is veranderd? 8)7


@RWB: Dat is inderdaad een stuk beter! Doordat ik onervaren ben, had ik niet aan het onclick event gedacht. Ik doe het nu als volgt:

offtopic:
c# staat niet bij de UBB-codes :)

C#:
1
2
3
4
5
6
7
8
9
10
11
private void FirstButton_Click(object sender, System.EventArgs e)
{
    // ophalen gegevens weggelaten
    string issueID = dr["issue_nr"].ToString();
    string recID = dr["rec_id"].ToString();
    if (_saveIssue.Value.Equals("true")) 
    {
        SaveIssue();
    }
    Response.Redirect("IssueDetail.aspx?issueID="+issueID+"&recID="+recID);
}

Die 2 hidden fields heb ik verwijderd, dat was helemaal nergens voor nodig.

Die js-code heb ik in een functie gestopt en hardcoded in de aspx-code gezet. De 2 regels voor rec_id en issue_id heb ik natuurlijk weggehaald.

En natuurlijk m.b.v. attributes een onclick event toegevoegd.

Doordat dit mijn eerste ASP-project is, heb ik daar niet aan gedacht... Ik dacht alleen maar in de trend van serverside-buttonclick-events (leuk woord voor galgje :)) en daar een script genereren en met registerClientScriptBlock toevoegen.

Hardstikke bedankt _/-\o_ ! Herkt toppie en er is dus maar 1 postback nodig :D

[ Voor 32% gewijzigd door Verwijderd op 07-10-2005 15:25 ]


  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
Verwijderd schreef op vrijdag 07 oktober 2005 @ 15:22:
[...]
Hoe doe je dit precies?? Ik had zelf het idee om aan elk invoerveld een onchange-javascript te hangen die vervolgens een hidden variabele instelt. Je kunt toch niet serverside weten of er clientside iets is veranderd? 8)7
in mijn geval ging het om de volgende situaties:

soms heb je op 1 form een aantal postbacks voor je wilt gaan saven. sommige controls doen dat nou eenmaal. Als je postbacked, dan is de waarde van je javascript variabele verloren gegaan. Deze moet je dus persisten.

soms heb je dat je iets edit serverside. er zijn dus dan al wijzigingen zonder dat je een textbox hebt gewijzigd clientside. in dat geval moet je wel vragen of je de wijzigingen op wilt slaan.

Verwijderd

Topicstarter
joopst schreef op vrijdag 07 oktober 2005 @ 15:40:
[...]


in mijn geval ging het om de volgende situaties:

soms heb je op 1 form een aantal postbacks voor je wilt gaan saven. sommige controls doen dat nou eenmaal. Als je postbacked, dan is de waarde van je javascript variabele verloren gegaan. Deze moet je dus persisten.
Oke, je slaat de waarde van ischanged serverside op als ik het goed begrijp?
soms heb je dat je iets edit serverside. er zijn dus dan al wijzigingen zonder dat je een textbox hebt gewijzigd clientside. in dat geval moet je wel vragen of je de wijzigingen op wilt slaan.
Je bedoelt dat je serverside textboxen gaat wijzigen? Waarom zou je dit doen?? Dit is iig niet van mij op toepassing.

Tevens treden er tussentijd geen postbacks op, er zijn maar een paar knoppen:

- Voeg nieuw record toe
- Voer wijzigingen door
- Volgende/vorige/...
- Annuleren (sluit venster).

Dus ik denk niet dat ik het server side ga bijhouden...

  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
zoals je het nu hebt, moet in elke eventhandler van elke button de volgende code plaatsen:
code:
1
2
3
4
5
6
7
8
    // ophalen gegevens weggelaten
    string issueID = dr["issue_nr"].ToString();
    string recID = dr["rec_id"].ToString();
    if (_saveIssue.Value.Equals("true")) 
    {
        SaveIssue();
    }
    Response.Redirect("IssueDetail.aspx?issueID="+issueID+"&recID="+recID);

dit is wat lastig als je ook 'gewone' html links hebt die van je pagina afnavigeren.
ook is het lastig als je stukken code wilt hergebruiken (met bijv. usercontrols)
in het geval van de 'gewone' html links kom je nl helemaal niet op de server en in het geval van usercontrols weet je niet welke save-method je aan moet roepen, omdat dit op verschillende plekken in je app wel eens anders zou kunnen zijn. Of je hebt usercontrols waarvan je de broncode niet tot je beschikking hebt.

om dit op te lossen heb ik een speciale 'ask-save-changes'-control (ascc) gemaakt, en een custom basepage (erft van system.web.ui.page). Als er mbv javascript bevestigd is dat de wijzigingen opgeslagen moeten worden, dan zet ik met javascript het controlId van de control waar op is geklikt als value van een hidden input die hoort bij de ascc. Dan submit ik niet de oorspronkelijk geklikte button, maar mijn eigen ascc mbv javascript
code:
1
__doPostBack(asccId,'');


Deze ascc zorgt voor het aanroepen van een generieke save method (of event) op de basepage waar per pagina dan een implementatie voor gemaakt moet worden. EN DAN komt de grote truuk van de maand. Op de basepage heb ik de volgende code gemaakt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        ' make protected sub public
        ' used for 'asksavechanges-functionality' -> now we can simulate 2 controls being clicked
        Public Overloads Sub RaisePostBackEvent(ByVal controlId As String, ByVal args As String)

            If ((Not controlId Is Nothing) AndAlso (controlId.Length > 0)) Then
                Dim control1 As Control = Me.FindControl(controlId)
                If ((control1 Is Nothing) OrElse Not TypeOf control1 Is IPostBackEventHandler) Then
                    Return
                End If

                Me.RaisePostBackEvent(CType(control1, IPostBackEventHandler), args)
            End If

        End Sub

ik heb de raispostback sub geoverload zodat ik hem aan kan roepen vanuit met ascc. Standaard is deze namelijk protected. Dit heb ik gedaan mbv de reflector.
Met deze truuk kan ik programatically doen alsof er op 2 buttons is geklikt :7

de ascc voert de volgende code uit:
code:
1
2
3
4
5
            If Me.SubmittedClientId.Length > 0 Then
                myPage = CType(Me.Page, HRS.Web.UI.BasePage) 'eigen basepage

                myPage.RaisePostBackEvent(Me.SubmittedClientId, String.Empty)
            End If

vanuit de app gezien wordt nu de oorspronkelijk geklikte button geklikt. Maar dan heb ik al de wijzigingen opgeslagen. En de click-event-handler van de oorspronkelijke button niet aangepast.

  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
Misschien beetje overkill voor jouw scherm, maar als je een keer wat grotere app gaat maken, dan zul je de search van got misschien nog wel gebruiken :)

Verwijderd

Topicstarter
joopst schreef op vrijdag 07 oktober 2005 @ 16:04:
Misschien beetje overkill voor jouw scherm, maar als je een keer wat grotere app gaat maken, dan zul je de search van got misschien nog wel gebruiken :)
Dit is volgens mij niet behandeld... Ik heb wel gezocht (weet de keywords niet meer), maar kon niets vinden.

Jouw stuk code moet ik nog even 10x lezen denk ik voordat ik het begrijp :).

  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
ik bedoel ook niet dat het al behandeld is, maar dat ie het dan terug kan zoeken :)
Pagina: 1