If draft exists, append. If not, create new draft

Js newbie here. I have seen a few actions which either append to an existing draft (if it exists), or create a new draft (if it doesn’t exist). I have attempted to recreate this with no success.

My end goal here is to:

  • Query a draft by title (title = [[date|%Y-%-m-%-d]])
  • if that draft hasn’t been created yet/doesn’t exist, Create a new draft with Today’s Date as title
  • If it already exists, append To that draft.

Appreciate any tips/advice thanks!

Try the code below. I’ve set it up as a function with parameters for the title, the text to insert and an optional parameter if you would like to force the loading of the updated draft into the editor.

Hopefully, you will get the gist, but there is a bit where I’ve taken a shortcut just for example purposes as you didn’t cover it in your use case. That’s the case where there are multiple drafts with the same title. It isn’t impossible and the inbuilt search function I’ve used will actually also match on partials, so the deal’s the same for that (though you could limit it to exact title matches only with a broader search and some extra processing). If the search returns non-unique matches, you get a prompt asking if you want to append to the first match. It gives you its title and you get an indicator at the top of how many matches were found.

I’ve also, for now, accounted for if the draft is already loaded in the editor. Sometimes, if you are editing the draft when you update it, the editor can lose the change. In those cases, rather than updating the draft I’ve opted to update the editor content.

I’ve added some details at the end about this behaviour.

Any questions, just note them below and I, or someone else on the forum will probably be able to help.

insertContent(draft.processTemplate("[[date|%Y-%-m-%-d]]"),"The text to be appended.");

function insertContent(p_strTitle, p_strInsert, p_bLoad = true)
{

	let ad = Draft.queryByTitle(p_strTitle);
	if(ad.length == 0)
	{
		//Create a new draft
		let dNew = new Draft();
		dNew.content = p_strTitle + "\n" + p_strInsert;
		dNew.update();
		if(p_bLoad) editor.load(dNew);
		return dNew;
	}
	if(ad.length == 1)
	{
		//The editor can sometimes conflict (race) with updating the loaded draft
		//so we might need to take an alternate editor based approach
		if(draft.uuid == ad[0].uuid)
		{
			//Update the draft in the editor
			editor.setTextInRange(editor.getText().length, 0, "\n" + p_strInsert);
		}
		else
		{
			//Update an existing draft
			ad[0].append(p_strInsert);
			ad[0].update();
		}
		
		//Load the appropriate draft into the editor
		if(p_bLoad) editor.load(ad[0]);
		else editor.load(draft);
		return ad[0];
	}
	//If we got here we have more than one match.
	//We could have full or partial duplicates (e.g. the date forms part of the 
	//title for another draft). For this example, I will
	//have Drafts give a yes no option, then update based on that
	//Modify this if you wish to pop up a prompt to choose a draft, 
	//fail outright with an error, etc.
	let pAsk = Prompt.create();
	pAsk.title = `Duplicate Drafts (${ad.length})`;
	pAsk.message = `Do you want to update the first draft?
"${ad[0].title}"`;
	pAsk.addButton("Yes");
	pAsk.addButton("No");
	pAsk.isCancellable = false;
	if (pAsk.show())
	{
		//User said yes, so update the first draft
		if (pAsk.buttonPressed == "Yes")
		{
			//The editor can sometimes conflict (race) with updating the loaded draft
			//so we might need to take an alternate editor based approach
			if(draft.uuid == ad[0].uuid)
			{
				//Update the draft in the editor
				editor.setTextInRange(editor.getText().length, 0, "\n" + p_strInsert);
			}
			else
			{
				//Update an existing draft
				ad[0].append(p_strInsert);
				ad[0].update();
			}
			
			//Load the appropriate draft into the editor
			if(p_bLoad) editor.load(ad[0]);
			else editor.load(draft);
			return ad[0];
		}
	}

	//Return void
	return;
}

The Timing Issue

@agiletortoise, updating the current draft doesn’t normally have a timing issue for updates, but here, I think it is introduced by being linked to the queryByTitle() function. When I run the code below on latest Mac beta, I sometimes get an update and sometimes I don’t. No particular pattern, which makes me think there’s a race going on somewhere.

// Ensure a draft with a unique title is loaded in the app editor for this test

// Get the title of the current draft 
let ad = Draft.queryByTitle(draft.title);

// Append 'foo' to the first returned draft in the array and update the draft
ad[0].append("foo");
ad[0].update();

// RESULT: draft in editor is only sometimes updated in the editor

EDIT
And now I’m in bed reading, I’ve jut realised that if I check the UUID matches, instead of updating ad[0], I could just update draft instead of adopting an editor approach. :confounded:

1 Like

Awesome! That seems to be working beautifully.

One thing I’m still trying to get my head around:

insertContent(draft.processTemplate("[[date|%Y-%-m-%-d]]"),"The text to be appended.");

Is this what allows you to query a title that is a template, rather than - say - a plain english title like “Today”?

draft.processTemplate("[[date|%Y-%-m-%-d]]" processes the template tag and outputs the evaluated text. That evaluated text is then used as the title to search for by the function being called.