How to add an object to a document when a button is pressed?

I’m making a live editor that would allow me to edit and add objects to a document, and then use the list in other documents. I would like to make these documents more like database tables with rows in them that will be XObjects attached to the document.

So far I got this:
chrome_3oKtKwm7RV

For editing of properties, I looked at the editableProperty.js code and managed to edit the properties of existing objects successfully.

After I input text in the input fields and press on the Add new Person button, I’d like it to add the object of the Person class with the specified fields But I can’t find it anywhere how to add objects to the document. I went through these guides: Scripting API Guide, XWiki JavaScript API, FAQ Tutorial(Manual), Structured data access API (EXPERIMENTAL), Structured data access JS API (EXPERIMENTAL) and other guides, but I can’t find information on how to add and delete objects.

In Velocity I can do:

## Create an object
#set($obj = $doc.newObject("XWiki.SomeClass"))
$obj.set("field1",$value1)
$obj.set("field2",$value2)

## Save the object in the page
$doc.save()

As shown in the Scripting API Guide, but I don’t understand how to do this when the button is pressed.

Hi,
I use the following concept:

You need 2 things:

First:

A javascript routine is needed which is activated by an event (e.g. onclick=, onchange= …)
This routine should generate an ajax call which invokes a wiki page which contains script code (velocity, groovy …). This script code changes the object.

This javascript code contains stuff to generate the ajax request like:

      var Url = new   XWiki.Document('WebHome','localtools.updateObject').getURL('get');

      var UrlParams = { 'xpage': 'plain',                  // this is really needed !
                                   'outputSyntax': 'plain',       // this is really needed !

                                 'parameter1' :'anything1',
                                 'parameter2' :'anything2',
                                 'parameter3' :  JSON.stringify(A_list_of_keys),
                                 'parameter4' :  JSON.stringify(A_list_of_values)
                        };

      require(["jquery"],function($) {
      $.get( Url, UrlParams, function( data ) {
        }, "json" );
  });

The URL-Parameter “xpage=plain” and “outputSyntax=plain” are needed to avoid any additional HTML output from the wiki, when doing the ajax request.
The additional parameters (1…4) are examples to give the information to your called document.

Second:
A document with velocity or javascript code:
In this example the document “localtools.updateObject.WebHome” is called.

It can refer the parameter values with (velocity) “$request.parameter1”, “$request.parameter2” … or within groovy without “$”.
This code should do the wanted actions to create objects.

Typically results may be returned to the javascript with
jsontool.serialize(SOME_RESULT)

I hope this helps

Norbert

1 Like

Thanks a log. I managed to implement it following your instructions.

Added ObjectAdd page:

{{velocity wiki="false"}}
#macro(addObject $classVar $inputJsonObject $pageObjectOut)
  #set($newPageObject = $objectsContainerPage.newObject($classVar.name))
  #set($discard = $pageObjectOut.put("object", $newPageObject))

  #foreach($classProperty in $classVar.properties)
    #set($classPropertyName = $classProperty.name)
    #set($jsonPropertyValue = $inputJsonObject.get($classPropertyName))
    #if($jsonPropertyValue)
      #set($discard = $newPageObject.set($classPropertyName, $jsonPropertyValue))
    #end
  #end
#end

#if($request.outputSyntax == "plain" && $request.xpage == "plain") ## If AJAX call
  #if(!$request.className)
    #set($myResponse = {"success": false, "errorReason": "User must provide className query key"})
  #elseif(!$request.documentReference)
    #set($myResponse = {"success": false, "errorReason": "User must provide documentReference query key"})
  #else
    #set($discard = $response.setContentType('application/json'))
    #set($docRefDescriptor = $jsontool.parse($request.documentReference))
    #set($documentReference = $services.model.createDocumentReference($docRefDescriptor.wikiName, $docRefDescriptor.spaceNames, $docRefDescriptor.documentName))
    #set($objectsContainerPage = $xwiki.getDocument($documentReference))
    #set($className = $request.className)
    #set($objectClass = $xwiki.getClass($className))
    #set($newObject = {})
    #set($newObjectList = [])
    #set($objectArgument = {})
    #set($objectsJson = $request.get("objects"))
    #if($objectsJson)
      #set($personInputObjects = $jsontool.parse($objectsJson))
      #if($personInputObjects)
        #foreach($personInputObject in $personInputObjects)
          #addObject($objectClass, $personInputObject, $objectArgument)
          #set($discard = $newObjectList.add($objectArgument.object))
        #end
      #end
    #end

    #set($discard = $objectsContainerPage.save())
    #set($classProperties = [])
    #foreach($classProperty in $objectClass.properties)
      #set($discard = $classProperties.add($classProperty.name))
    #end
    #set($myResponse = {"success": true, "wikiName": $docRefDescriptor.wikiName, "documentName" : $docRefDescriptor.documentName, "xWikiClass": $objectClass.name, "classProperties" : $classProperties, "documentReference": $request.documentReference, "docRefDescriptor": $jsontool.serialize($docRefDescriptor)})
    
    #set($newObjectsInformationList = [])
    #foreach($newObject in $newObjectList)
      #set($newObjectInformation = {})

      #foreach($classProperty in $objectClass.properties)
        #set($propertyMap = {})
        #set($objectPropertyValue = $newObject.getValue($classProperty.name))
        #if($objectPropertyValue)
          #set($discard = $propertyMap.put("value", $objectPropertyValue))
          #set($propertyReference = $newObject.getPropertyReference($classProperty.name))
          #set($discard = $propertyMap.put("dataProperty", $escapetool.xml($services.model.serialize($propertyReference))))
          #set($discard = $newObjectInformation.put($classProperty.name, $propertyMap))
        #end
      #end

      #set($discard = $newObjectsInformationList.add($newObjectInformation))
    #end
    #set($discard = $myResponse.put("objects", $newObjectsInformationList))
  #end
  $jsontool.serialize(${myResponse})
#end
{{/velocity}}

It’ll do for the start. One thing I found when I was trying to figure out how to do this properly is that there is already rest interface to delete, edit and add objects. And also dataeditors.js that takes advantage of it. But I decided to write my own page still for now, because that dataeditors.js has a 800-lines long function which I couldn’t understand.