Need to get the 2sxc Field Type from an Entity - razor

After getting everything working on this previous question Is there a way to Clone one or many Entities (records) in Code, I wanted to clean it up and make it more useful/reusable. So far, I am deciding how to copy/add the field using the content-type field names, so attribute.Key inside the foreach on Attributes. What I need instead is to know the Entity field's Type; meaning String, Number, Hyperlink, Entity, etc.
So I want something like if(AsEntity(original).FieldType == "HyperLink") { do this stuff }. I have explored the API docs but have not spotted how to get to the info. Is it possible?
I did figure out that the attribute.Value has a Type that I could use to answer most of them, but Hyperlink and String are both showing, System.String.
Here are, in order, String, Hyperlink, Entity, and Number:
atts: ToSic.Eav.Data.Attribute`1[System.String]
atts: ToSic.Eav.Data.Attribute`1[System.String]
atts: ToSic.Eav.Data.Attribute`1[ToSic.Eav.Data.EntityRelationship]
atts: ToSic.Eav.Data.Attribute`1[System.Nullable`1[System.Decimal]]
So is there a way from the Entity or its Attributes or some other pathway of object/methods/properties to just get the answer as the field Type name? Or is there a wrapper of some kind I can get to that will let me handle (convert to/from) Hyperlinks? I am open to other ideas. Since the fields.Add() is different by "FieldType" this would be really helpful.

It's kind of simple, but needs a bit more code because of the dynamic nature of Razor. Here's a sample code that should get you want you need:
#using System.Collections.Generic;
#using System.Linq;
#using ToSic.Eav.Data;
var type = AsEntity(Content).Type;
var attributes = type.Attributes as IEnumerable<IContentTypeAttribute>;
var typeOfAwards attributes.First(t => t.Name == "Awards").Type; // this will return "Entity"
I created a quick sample for you here: https://2sxc.org/dnn-tutorials/en/razor/data910/page

Related

concatenate variables in angular property element

I comment, and looked here and I can not find the solution, my problem is the following:
in my html template in angular, I need to pass a series of data to the metadata property of a button, I can't get the correct way to successfully concatenate the variable that contains the value.
this should be the html element:
<mati-button clientId="clientId" flowId="flowId" color="green"metadata='{"user_id":"1234778","email":"som#som.com"}'/>
I tried several ways but I can't insert the respective values....
example:
<mati-button metadata='{"userID": "{{user.id}}" }'></mati-button>
unsuccessfully...
Assuming mati-button is an Angular component with metadata as Input(), you are probably looking for
<mati-button
[clientId]="clientId"
[flowId]="flowId"
[color]="green"
[metadata]="{ userId: '1234778', email: 'som#som.com'}"
></mati-button>
See the guide on property binding to learn more:
To bind to an element's property, enclose it in square brackets, [], which identifies the property as a target property. [...] The brackets, [], cause Angular to evaluate the right-hand side of the assignment as a dynamic expression. Without the brackets, Angular treats the right-hand side as a string literal and sets the property to that static value.
By "dynamic expression" they mean JS-expressions, i.e., a public variable available through the component's TypeScript, a boolean expression, an array, or, like in your case, a JS-object that you can construct inline.
You can try doing this
<mati-button metadata="{'userID': user.id }"></mati-button>
metadata='{" userID ": {{user.id}}}'
in the end I got it. Apparently I don't know why, but the third-party script hides that parameter and it couldn't be debugged in the console, but it does receive them without any problem! Thanks everyone for your help!

How to Retrieve Values from a Class Within a Class Using JavaScript

I am not experienced with HTML and 'JavaScript', and is having a roadblock when attempting to check the values from a class.
Below is the source as seen from F12
I would like to retrieve all createdby text -muted values (as they may contain more than one row) to check if any of them matches SYSTEM, may I know how can it be done?
I understand that an image is not the best way to portrait my question, I will try to type the source in my question.
My apologies, and thank you.
You can get NodeList which contains createdby text-muted classes using document.querySelectorAll as follows.
const elems = document.querySelectorAll(".createdby .text-muted");
elems.forEach((item) => {
console.log(item.innerHTML); // This will contain the text value of the selected selector
});

Using JSON.stringify but SSJS variant in XPages

for an application I am building an administration panel where a power user should be able to check the JSON structure of a selected object.
I would like to display the JSON object in a computed text field but display/format it nicely so it is better human readable, something similar as in pretty print.
Is there any function I could use in SSJS that results in something similar so I can use display json nicely in computed text / editable fields?
Use stringify's third parameter "space":
JSON.stringify(yourObject, null, ' ');
space
A String or Number object that's used to insert white
space into the output JSON string for readability purposes. If this is
a Number, it indicates the number of space characters to use as white
space; this number is capped at 10 if it's larger than that. Values
less than 1 indicate that no space should be used. If this is a
String, the string (or the first 10 characters of the string, if it's
longer than that) is used as white space. If this parameter is not
provided (or is null), no white space is used.
As XPages doesn't support JSON.stringify yet you can include JSON's definition as SSJS resource and use it.
As Knut points out, you can certainly add json2.js to XPages; I've previously used an implementation as Marky Roden's post outlines. This is probably the "safest" way of doing so, from the SSJS side of things.
It does ignore the included fromJson and toJson SSJS methods provided out of the box in XPages. While imperfect, they are functional, especially with the inclusion of Tommy Valand's fix snippet. Be advised, using Tommy's fix does wrap responses to ensure a proper JS object can be parsed by shoving an Array into an object with a values property for the array; so no direct pulling of an Array only.
Additionally, I believe it would be useful to point out that a bean, providing a convenience method or two as wrappers to use either the com.ibm.commons.util.io.json methods to abstract the conversion method, or switching in something like Google GSON, might be more powerful and unified, based on your style of development.
Knut, Eric, I came so far myself already.
function prettyPrint(id) {
var ugly = dojo.byId(id).value;
var obj = $.parseJSON( "[" + ugly + "]" );
var pretty = JSON.stringify(obj, undefined, 4);
dojo.byId(id).innerHTML = pretty;
}
and I call it e.g.
var name = x$('#{id:input-currentObjectCollectionFiltered}').attr("name");
prettyPrint(name);
I tried to make use the x$ function but was not able to make the ID dynamic there e.g.
var ugly = x$('#{id:" + id + "}').val();
not sure why. would be nicer if I just would call prettyPrint('input-currentObjectCollectionFiltered'); and the function would figure it out.
Instead of dojo.byId(id).value I tried:
var ugly=$("#" + id).val();
but things returns and undefined object: I thought jquery would be smarter to work with dynamic id's.
anyway stringify works just fine.

Need Validation on html dropdownlist with data from Viewbag

I know I'm not supposed to use the Viewbag and that I should build a menu using Html.DropDowlListFor() so that i can add attribute bound to the members of the model, BUT, that would involve a pretty extensive code rewrite....
I have a custom controller with a menu:
*.ASCX
<%: Html.DropDownList("CityIDs", new SelectList(ViewBag.cities, "Id", "Name"), "--Select--", new { style = "width:200px" })%>
<%= Html.ValidationMessage("CityIDs") %>
The List populates just fine and I can default to the top item to "--Select--"
The prbolem is that I want the validation error to occur on anything that is not from the viewbag.... how can I achieve this?
Validation for dropdown lists only ensures that something was posted. If you want to ensure that the value that was posted is actually one of a set of "allowed" values, then you'll have to manually do that in your post action:
var cityIds = db.Cities.Select(m => m.Id);
if (!cityIds.Contains(model.CityIDs))
{
ModelState.AddModelError("CityIDs", "You must select one of the available choices.");
}
if (ModelState.IsValid)
{
...
Two things:
Notice that I'm pulling the city ids straight from the database (the actual code you'd need here, of course, depends on your specific implementation). The important thing, though, is that ViewBag only survives a single request, so you can't look for them in ViewBag after posting.
Despite the pluralized name of CityIDs, using the DropDownList helper ensures that only a single selected value will exist. If this is actually supposed to be a multiselect, then you need to use ListBox instead, and update this conditional here to account for check for multiple values.
Populates the top item with Text = "--Select--" and Value = ""
which will post a blank value for CityIDs and cause an error in ModelState.

AS3 Advanced Variable Usage - Retrieve Value In Variable Selected Based On Value In Another Variable

I am working on creating a project which allows me to define objects in an XML document and have flash create the required items and display at run time. Needless to say, it is slow progress making this up and learning as I go along.
I have now reached a hurdle, which by comparison should be really easy. But I'm drawing a blank. Despite spending several hours with my good friend Google, I don't seem to be able to phrase this in such as way as to find other people who want to achieve the same.
Description
Currently I have a menu handling class, which is where the issue lays. An instance of the menuHandler class is created. It is used by calling a class (LoadFramework) which is passed two strings. One is the address of an XML file, the other is a tag within that XML document to specify what part of it needs to be read.
The XML document is loaded by a class and then parsed into a variable. Then depending on the second string passed (the value of the XML tag), the appropriate part of that XML document is translated onto the screen. This all works fine, but here is the catch...
The only way I have managed to get this working is to use a switch statement with a case for every potential tag. Then I write an appropriate for-each-in loop. The following is an example of one of the case statements (they are all identical except for the "event.dat.XYZ.element" part). "event.dat" is a variable passed by a custom handler, it contains the XML data. XYZ is the name of the tag (in this case "home") and each "element" is a tag containing an attribute.
case "home":
for each (var menuField:XML in event.datPass.home.element) {
mnDataHold.push(menuFieldHome);
loopCount ++;
} // for each (var menuField:XML in event.datPass.home)
ActionMenu(loopCount);
break;
An example of the XML that is held in event.datPass.
<home label="home">
<element label="menuType">HomeScreen</element>
<element label="screenType">Game.assets.menuScreens.homeScreen</element>
<element label="buttonCoords">400,50,400,100,400,150,400,200</element>
<element label="buttonNames">baseButton,baseButton,baseButton,baseButton</element>
<element label="labelCoords">440,51,425,101,430,151,438,201</element>
<element label="labelTexts">Play,Options,Credits,More</element>
<element label="labelColors">0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF</element>
<element label="labelSizes">22,22,22,22</element>
<element label="labelBolds">true,true,true,true</element>
<element label="buttonCommands">startGame,diplaysMnuOptions,displayMnuCredits,displayMnuMoreGames</element>
</home>
The Request
What I want to do is replace part or all of the object in the for-each-in loop with a variable, and then evaluate the string as a reference rather than using it as the value.
So that I can end up ditching the switch and simply have something like:
for each (var menuField:XML in [mnVariable]) {
mnVariable would contain the string, eg "event.datPass.home.element".
Or:
for each (var menuField:XML in event.dat.[mnVariable].element) {
mnVariable would contain the string, eg "home".
However, written the first way, all that happens is that the for-each-in loop looks in mnVariable to find the value in menuField, which it won't find. Written the second way it will just throw an error. I need [mnVariable] to be used to evaluate as meaning 'look in the object named by this string'
Any pointers are very gladly received.
Generally not a fan of having data-defining element names in XML, but - assuming event.dat is actually an XML object, and not an arbitrary object that you've manually parsed the XML into (can't tell from the question) - this is really a question about ECMAScript for XML (E4X) rather than variables in general.
If so, this should work:
for each (var menuField:XML in event.dat.child(mnVariable).element)
{
// Do something
}
Can't test at the moment, but this may also work (it's part of E4X standard, but not sure if Adobe implemented it):
// Note, no dot before the indexer:
for each (var menuField:XML in event.dat[mnVariable].element)
{
// Do something
}
The latter is also generally the way to access a property of an object using a string property name, so if event.dat is an arbitrary object of manually parsed XML - as opposed to an actual XML object - the second example should also work.