CRAFTER: Is it possible to change the value of a specific attribute of a specific component? - crafter-cms

I was wondering if there is a solution to only change the value of an attribute in a specific component using the Crafter Studio API or a groovy script.
The only thing I have found is the method "Write Content"(https://docs.craftercms.org/en/3.0/developers/projects/studio/api/content/write-content.html) of the API but to only change one attribute you need to retrieve the entire component file, modify the value you need and push the entire file back, that is quite heavy.

Write content API is the only API that writes content at the moment.
If you're working on the UI, you could use our #craftercms/studio-ui package to write single fields easily as this is abstracted for you there.
yarn|npm install #craftercms/studio-ui
import { updateField } from '#craftercms/studio-ui/services/content'
updateField(
'yourSiteId',
'/path/of/the/xml/or/objectId/if/embedded.xml',
'idOfTheField_s',
indexOfItem, // If it is a collection (node-selector, or repeat group), send null otherwise,
parentModelId, // null unless you're working with embedded content
newValueOfTheField
).subscribe(() => {
console.log('Field update complete');
});

Related

How to return an output from javascript function using invoke js in blueprism

I want to read multiple key-value pairs from a webpage and write it to a collection using blueprism.
I want to use javascript.
I am able to read text from webpage but couldnt understand how to write that data into blueprism data item or a collection.
Blue Prism provides no facility to return data directly from a JavaScript call back into the calling Object. Your best bet is to use a script that generates a hidden input element in the DOM and appends the data you want to exfiltrate:
var hiddenElement = document.querySelector('#bp-output');
if (typeof hiddenElement === 'undefined') {
hiddenElement = document.createElement('input');
hiddenElement.type = 'hidden';
hiddenElement.id = 'bp-output';
document.body.appendChild(hiddenElement);
}
hiddenElement.value = /* some functionality to set the value of the newly-created hidden element */;
You'll need to model this element in your object's application modeler, but it's fairly simple to do - you don't need to match on any attributes other than "ID" or "Web ID", and it's a match only to the string bp-output.
From there, you can use a typical Read stage to read the value out of the value attribute of your element.
For more complex data structures like Collections, you will have to utilize some serialization trickery to get to where you want to be. For example, if you're trying to read a table into a Collection via JavaScript, your /* functionality to set the value of the newly-created hidden element */ in the example above may need to leverage some code from this SO thread to serialize the table itself to a CSV string. Once you've read the string from the hidden element's value, you could use the CSV-related actions in the vendor-provided Utility - Strings VBO to serialize this to a proper Collection for your use in your Objects/Processes.

Using set to only update a subset of write properties in a Firestore transaction

Is it possible to use set (within the context of a transaction) to create a document with some object, but only update it with a subset of properties?
For example, I have a use case where I'd like to create or update a document, but in the update case only certain fields should be merged. In the code below, created should only be written on document creation (and not on update).
I've tried mergeFields in SetOptions which I thought would only apply to the update case, but seems to apply to the write case as well and causes created to be omitted when creating the document.
If that's the intended behaviour of SetOption is there another way to achieve this?
t.set(docRef,
{
name: 'Alice',
updated: admin.firestore.FieldValue.serverTimestamp(),
created: admin.firestore.FieldValue.serverTimestamp(),
},
{ mergeFields: ['name', 'updated'] });
Node.js Admin SDK 9.2.0
Seems like your transaction will first have to read the document with get() to create or update, then make a decision about what to pass to set() in order to make sure the document contains the correct fields. A single set() cannot make this decision for you. So, something like:
const snap = await t.get(docRef)
if (snap.exists) {
t.update(docRef, ...)
}
else {
t.create(docRef, ...)
}

get default value from Default Value control in Maximo autoscript

In a Maximo 7.6.0 automation script, I can get the default value from the Default Value in Database Configuration with a chain of calls like this:
mbo.getThisMboSet().getMboSetInfo().getMboValueInfo("WONUM").getDefaultValue()
If there is a textbox with inputmode="default", I can get that default value with a chain of calls like this:
mbo.getThisMboSet().getDefaultValue("WONUM")
If there is also a Default Value control in play, what is the chain of calls to get that default value? (The calls above still return the same things.)
It doesn't look like there is an easy way to get this data via some helper method like those. The setAppDefaultValue() method reads these values in and applies them to the MBO at some point during the load or init of the MBO.
According to the JavaDocs for that method (https://developer.ibm.com/static/site-id/155/maximodev/7609/maximocore/businessobjects/psdi/mbo/Mbo.html#setAppDefaultValue()), the data is stored in the appfielddefault table, if you wanted to pursue that route.
Looking through the code of that method, it fetches a few pieces of information and then uses the data dictionary to get all of that default data (via the following line).
/* 7320 */ HashMap defaultAppVal = getMboServer().getMaximoDD().getAppFieldDefaults(appStr.toUpperCase(), getMboSetInfo().getObjectName().toUpperCase(), siteStr, getUserName().toUpperCase(), groupSet);

How to add collections in transformations when writing(creating) a Document in MarkLogic

I wrote a transformation in xquery which unquotes an XML-String and inserts a element with its content. This works fine.
I need to create a collection dependant on the root element of this element as well. I can't do this on new documents as xdmp:document-add-collections() is not working. How do I add the collection to new Documents in transformations?
Here my ServerSide xQuery Code:
xquery version "1.0-ml";
module namespace transform = "http://marklogic.com/rest-api/transform/smtextdocuments";
import module namespace mem = "http://xqdev.com/in-mem-update" at '/MarkLogic/appservices/utils/in-mem-update.xqy';
declare function transform(
$context as map:map,
$params as map:map,
$content as document-node()
) as document-node()
{
let $uri := base-uri($content)
let $doccont := $content/smtextdocuments/documentcontent
let $newcont := xdmp:unquote($doccont)
let $contname := node-name($newcont/*)
let $result := if ( exists($content/smtextdocuments/content))
then mem:node-replace($content/smtextdocuments/content, <content>11{$newcont}</content>)
else mem:node-insert-after($doccont, <content>{$newcont}</content>)
let $log := xdmp:log($content)
return (
$result,
xdmp:document-add-collections($uri, fn:string($contname)),
xdmp:document-remove-collections($uri, "raw")
)
};
The script ist running with the java api (4.0.4) create methode via parameter ServerTransform transform. As per documentation the transformation script is running before the document is stored in the Database.
Its a new document; I need to transform the content and then create the collection.
I can see the document after the create, the content is available. Just the collection is missing. I can try xdmp:document-insert method but is it correct writing the document while create is running?.
The transform mechanism of the Java API / REST API takes responsibility for the document write. At present, there's no way for the transform to supply collections to the writer. That would be a reasonable request for enhancement.
The transform shouldn't attempt to write the document, because the writer would also attempt to write the same document.
One alternative would be to transform the document in Java before writing it and specify the collection as part of the write request.
Another alternative would be to rewrite the transform as a resource service extension, implement the write within the resource service extension, and modify the Java client to send the document to the resource service extension.
Depending on the model, a final alternative might be to use a range index on an element within the document to collect documents into sets instead of using a collection on the document.
Hoping that helps,
What do you mean by "new documents"? Is the document already inserted into the MarkLogic database at the time you are adjusting the collections of it? If not, you may want to modify your return to ($result, xdmp:document-insert($uri, $result, xdmp:default-permissions(), fn:string($contname)) ) for that case.
Otherwise, can you edit your question to share the error or problem more specifically you are facing?
It is a pity that REST transforms do not allow this, like MLCP transforms do. Until changed you have the options drawn by ehennum, or you can consider delaying adding of collections to a pre- or post-commit trigger. It takes some overhead, but it sometimes makes perfect sense to do something like that in a trigger, since it makes sure it is always enforced, and a good place to do content validation, audit logging, and things like that as well.
HTH!

Incremental loading in Azure Mobile Services

Given the following code:
listView.ItemsSource =
App.azureClient.GetTable<SomeTable>().ToIncrementalLoadingCollection();
We get incremental loading without further changes.
But what if we modify the read.js server side script to e.g. use mssql to query another table instead. What happens to the incremental loading? I'm assuming it breaks; if so, what's needed to support it again?
And what if the query used the untyped version instead, e.g.
App.azureClient.GetTable("SomeTable").ReadAsync(...)
Could incremental loading be somehow supported in this case, or must it be done "by hand" somehow?
Bonus points for insights on how Azure Mobile Services implements incremental loading between the server and the client.
The incremental loading collection works by sending the $top and $skip query parameters (those are also sent when you do a query by using the .Take and .Skip methods in the table). So if you want to modify the read script to do something other than the default behavior, while still maintaining the ability to use that table with an incremental loading collection, you need to take those values into account.
To do that, you can ask for the query components, which will contain the values, as shown below:
function read(query, user, request) {
var queryComponents = query.getComponents();
console.log('query components: ', queryComponents); // useful to see all information
var top = queryComponents.take;
var skip = queryComponents.skip;
// do whatever you want with those values, then call request.respond(...)
}
The way it's implemented at the client is by using a class which implements the ISupportIncrementalLoading interface. You can see it (and the full source code for the client SDKs) in the GitHub repository, or more specifically the MobileServiceIncrementalLoadingCollection class (the method is added as an extension in the MobileServiceIncrementalLoadingCollectionExtensions class).
And the untyped table does not have that method - as you can see in the extension class, it's only added to the typed version of the table.

Resources