How to call UpdateListItems from Link

Jun 17, 2014 at 5:16 PM
Edited Jun 17, 2014 at 5:17 PM
I have a custom DVWP with a list of items using an aggregate data source. In the XSLT I have a link to delete child items. My requirement is to provide one click delete. I have a solution in place using UpdateListItems that works fine. However, I have to make each instance of the script unique. My question: is there a way to pass values from an <a> tag to the script? Although performance is fine during testing, I would like to make the code cleaner if possible.

Just to be clear I would like to pass the item ID and perhaps the List Name from the link to the script similar to how OpenPopUpPage works in OTB SharePoint 2010 (onclick="javascript:OpenPopUpPage('{$editPOC}', RefreshPage, 850, 500); javascript:return false;")

Here is the <a> tag I am using (some text removed for brevity):
<a id="{concat(@ID,'DeletePocAssociation')}" title="" href="#"><img alt="" src="/_layouts/images/CMSUNLINK.gif"/></a>
Here is the script I have embedded in the XSLT:
<script type="text/javascript">
    $(document).ready(function() {
        $("a[id='<xsl:value-of select="concat(@ID,'DeletePocAssociation')"/>']").click(function() {
            delPocAssoc<xsl:value-of select="concat(@ID,'DeletePocAssociation')"/>();
        });
    });
    function delPocAssoc<xsl:value-of select="concat(@ID,'DeletePocAssociation')"/>() {
        $().SPServices({
            operation: "UpdateListItems",
            async: false,
            batchCmd: "Delete",
            listName: "OP POC",
            ID: <xsl:value-of select="@ID"/>,
            debug: true,
            completefunc: refreshPage<xsl:value-of select="concat(@ID,'DeletePocAssociation')"/>
        });
    };
    function refreshPage<xsl:value-of select="concat(@ID,'DeletePocAssociation')"/>() {
        window.location.replace(&apos;<xsl:value-of select="string($thisPage)"/>&apos;);
    };
</script>       
Jun 18, 2014 at 2:02 AM
To make the code cleaner and more efficient, you shouldn't create a function and click handler for every item. What you should do is what you are already thinking; Add attributes to the <a> tag and with your 1 click handler, pick those attributes up on the fly and use them within your 1 function call.

I've created a fiddle, so you can, well fiddle around with that idea:
http://jsfiddle.net/iOnline247/eFqLB/

So to fit this within your DVWP, you will get rid of the logic of adding script for every row. Add logic to generate the attributes that are needed for each <a> within your XSLT, and finally within your XSLT after the row iteration, add a simple <script> block with the code from the fiddle. You'll need to tweak the script accordingly though.

Cheers,
Matthew
Marked as answer by Arknev on 6/18/2014 at 10:37 AM
Coordinator
Jun 18, 2014 at 3:10 PM
What Matt said. You shouldn't ever duplicate code where calling a function will do.

M.
Jun 18, 2014 at 6:37 PM
Edited Jun 20, 2014 at 4:49 PM
Fantastic, thank you Matthew and Marc. With some fiddling, and realizing that the "not a function" error was because I wasn't loading SPServices in JSFiddle, I have this working in my DVWP.

Below is the code I'm using,

Links from each row with test to determine if child exists or not and showing appropriate button.
<div class="" id="dataFeedsForSelected">

<xsl:if test="string-length($varGetOpDfID) &gt;= 1">

<a title="" href="#" class="btnChangeDfAssoc" data-id="{$varGetOpDfID}" data-list-name="OP Data Feed" data-batch-cmd="Delete" data-op-poc="NA" data-op-prj="{$pj}" data-df-id="NA"><img alt="" src="/_layouts/images/CMSUNLINK.gif"/></a>

</xsl:if>

<xsl:if test="string-length($varGetOpDfID) &lt; 1">

<a title="" href="#" class="btnChangeDfAssoc " data-id="NA" data-list-name="OP Data Feed" data-batch-cmd="New" data-op-poc="{$opp}" data-op-prj="{$pj}" data-df-id="{@ID}"><img alt="" src="/_layouts/images/addusergroup.gif"/></a>

</xsl:if>

</div>
The script, loaded after the <div> with the ID of dataFeedsForSelected
<script type="text/javascript">
    $(document).ready(function () {
        $("#dataFeedsForSelected").on("click", ".btnChangeDfAssoc", function (event) {
            event.preventDefault();
            var $this = $(this),
                data = $this.data(),
                id = data.id,
                listName = data.listName,
                batchCmd = data.batchCmd,
                opPoc = data.opPoc,
                opPrj = data.opPrj,
                dfId = data.dfId;
            if (batchCmd == "New") {
                {
                    $().SPServices({
                        operation: "UpdateListItems",
                        async: false,
                        batchCmd: "New",
                        listName: "OP Data Feed",
                        valuepairs: [
                            ["OPPOC", opPoc],
                            ["OnboardingProject", opPrj],
                            ["DataFeed", dfId]
                        ],
                        debug: true,
                        completefunc: refreshPage
                    });
                }
            }
            else if (batchCmd == "Delete") {
                {
                    $().SPServices({
                        operation: "UpdateListItems",
                        async: false,
                        batchCmd: "Delete",
                        listName: listName,
                        ID: id,
                        debug: true,
                        completefunc: refreshPage
                    });
                }
            }
        });
    });
    function refreshPage() {
        window.location.replace(&apos;<xsl:value-of select="$thisPage"/>&apos;);
    }
</script>
I hope someone else finds this helpful.

-Robert
Jun 20, 2014 at 4:50 PM
I ran into an issue using the console.log with IE. Described here:

http://stackoverflow.com/questions/7742781/why-javascript-only-works-after-opening-developer-tools-in-ie-once

I have removed the lines from the sample code in my response above.
Jun 21, 2014 at 3:32 AM
Edited Jun 21, 2014 at 3:33 AM
I'm glad it was helpful. :)

Note:
When you mix fiddling with production code, you may get errors. window.console statements are used for debugging purposes only and should always be stripped from any code you put into production. If you want to get fancy with your workflow, take a look at gruntjs or something similar to automate this process.

Cheers,
Matthew