How to get a list of all attributes(either set or not set) that are applicable for a specific tag in HTML?
For example, to get a list of all attributes that are applicable for tag...
Is JS method to do so?
Following are my imaginary JS methods describing my requirement...
document.getAllApplicableAttributesForTag('a');
OR
element = document.getElementsByTagName('a')[0];
element.getAllApplicableAttributes();
Is there any valid way to do it?
You can use element.attributes to get a list of all attributes.
or simply use getAttributes() from hotdom library to get all attributes in a proper format with more options.
const a = dom.select('a');
dom.getAttributes(a);
above code will return all attributes of the anchor tag.
[
{attr: "href", value: "#"},
{attr: "title", value: "foo"}
]
Haskell has become useful as a web language (thanks Servant!), and yet JSON is still so painful for me so I must be doing something wrong (?)
I hear JSON mentioned as a pain point enough, and the responses I've heard revolve around "use PureScript", "wait for Sub/Row Typing", "use esoterica, like Vinyl", "Aeson + just deal with the explosion of boiler plate data types".
As an (unfair) reference point, I really enjoy the ease of Clojure's JSON "story" (of course, it's a dynamic language, and has it's tradeoffs for which I still prefer Haskell).
Here's an example I've been staring at for an hour.
{
"access_token": "xxx",
"batch": [
{"method":"GET", "name":"oldmsg", "relative_url": "<MESSAGE-ID>?fields=from,message,id"},
{"method":"GET", "name":"imp", "relative_url": "{result=oldmsg:$.from.id}?fields=impersonate_token"},
{"method":"POST", "name":"newmsg", "relative_url": "<GROUP-ID>/feed?access_token={result=imp:$.impersonate_token}", "body":"message={result=oldmsg:$.message}"},
{"method":"POST", "name":"oldcomment", "relative_url": "{result=oldmsg:$.id}/comments", "body":"message=Post moved to https://workplace.facebook.com/{result=newmsg:$.id}"},
{"method":"POST", "name":"newcomment", "relative_url": "{result=newmsg:$.id}/comments", "body":"message=Post moved from https://workplace.facebook.com/{result=oldmsg:$.id}"},
]
}
I need to POST this to FB workplace, which will copy a message to a new group, and comment a link on both, linking to each other.
My first attempt looked something like:
data BatchReq = BatchReq {
method :: Text
, name :: Text
, relativeUrl :: Text
, body :: Maybe Text
}
data BatchReqs = BatchReqs {
accessToken :: Text
, batch :: [BatchReq]
}
softMove tok msgId= BatchReqs tok [
BatchReq "GET" "oldmsg" (msgId `append` "?fields=from,message,id") Nothing
...
]
That's painfully rigid, and dealing with Maybes all over is uncomfortable. Is Nothing a JSON null? Or should the field be absent? Then I worried about deriving the Aeson instances, and had to figure out how to convert eg relativeUrl to relative_url. Then I added an endpoint, and now I have name clashes. DuplicateRecordFields! But wait, that causes so many problems elsewhere. So update the data type to use eg batchReqRelativeUrl, and peel that off when deriving instances using Typeables and Proxys. Then I needed to add endpoints, and or massage the shape of that rigid data type for which I added more datapoints, trying to not let the "tyranny of small differences" bloat my data types too much.
At this point, I was largely consuming JSON, so decided a "dynamic" thing would be to use lenses. So, to drill into a JSON field holding a group id I did:
filteredBy :: (Choice p, Applicative f) => (a -> Bool) -> Getting (Data.Monoid.First a) s a -> Optic' p f s s
filteredBy cond lens = filtered (\x -> maybe False cond (x ^? lens))
-- the group to which to move the message
groupId :: AsValue s => s -> AppM Text
groupId json = maybe (error500 "couldn't find group id in json.")
pure (json ^? l)
where l = changeValue . key "message_tags" . values . filteredBy (== "group") (key "type") . key "id" . _String
That's rather heavy to access fields. But I also need to generate payloads, and I'm not skilled enough to see how lenses will be nice for that. Circling around to the motivating batch request, I've come up with a "dynamic" way of writing these payloads. It could be simplified with helper fns, but, I'm not even sure how much nicer it'll get with that.
softMove :: Text -> Text -> Text -> Value
softMove accessToken msgId groupId = object [
"access_token" .= accessToken
, "batch" .= [
object ["method" .= String "GET", "name" .= String "oldmsg", "relative_url" .= String (msgId `append` "?fields=from,message,id")]
, object ["method" .= String "GET", "name" .= String "imp", "relative_url" .= String "{result=oldmsg:$.from.id}?fields=impersonate_token"]
, object ["method" .= String "POST", "name" .= String "newmsg", "relative_url" .= String (groupId `append` "/feed?access_token={result=imp:$.impersonate_token}"), "body" .= String "message={result=oldmsg:$.message}"]
, object ["method" .= String "POST", "name" .= String "oldcomment", "relative_url" .= String "{result=oldmsg:$.id}/comments", "body" .= String "message=Post moved to https://workplace.facebook.com/{result=newmsg:$.id}"]
, object ["method" .= String "POST", "name" .= String "newcomment", "relative_url" .= String "{result=newmsg:$.id}/comments", "body" .= String "message=Post moved from https://workplace.facebook.com/{result=oldmsg:$.id}"]
]
]
I'm considering having JSON blobs in code or reading them in as files and using Text.Printf to splice in variables...
I mean, I can do it all like this, but would sure appreciate finding an alternative. FB's API is a bit unique in that it can't be represented as a rigid data structure like a lot of REST APIs; they call it their Graph API which is quite a bit more dynamic in use, and treating it like a rigid API has been painful thus far.
(Also, thanks to all the community help getting me this far with Haskell!)
Update: Added some comments on the "dynamic strategy" at the bottom.
In similar situations, I've used single-character helpers to good effect:
json1 :: Value
json1 = o[ "batch" .=
[ o[ "method" .= s"GET", "name" .= s"oldmsg",
"url" .= s"..." ]
, o[ "method" .= s"POST", "name" .= s"newmsg",
"url" .= s"...", "body" .= s"..." ]
]
]
where o = object
s = String
Note that the non-standard syntax (no space between one-character helper and argument) is intentional. It's a signal to me and others reading my code that these are technical "annotations" to satisfy the type checker rather than a more usual kind of function call that's actually doing something.
While this adds a little clutter, the annotations are easy to ignore while reading the code. They're also easy to forget while writing code, but the type checker catches those, so they're easy to fix.
In your particular case, I think some more structured helpers do make sense. Something like:
softMove :: Text -> Text -> Text -> Value
softMove accessToken msgId groupId = object [
"access_token" .= accessToken
, "batch" .= [
get "oldmsg" (msgId <> "?fields=from,message,id")
, get "imp" "{result=oldmsg:$.from.id}?fields=impersonate_token"
, post "newmsg" (groupId <> "...") "..."
, post "oldcomment" "{result=oldmsg:$.id}/comments" "..."
, post "newcomment" "{result=newmsg:$.id}/comments" "..."
]
]
where get name url = object $ req "GET" name url
post name url body = object $ req "POST" name url
<> ["body" .= s body]
req method name url = [ "method" .= s method, "name" .= s name,
"relative_url" .= s url ]
s = String
Note that you can tailor these helpers to the specific JSON you're generating in a particular case and define them locally in a where clause. You don't need to commit to some big chunk of ADT and function infrastructure that covers all JSON use-cases in your code, as you might do if the JSON was more unified in structure across the application.
Comments on the "Dynamic Strategy"
With respect to whether or not using a "dynamic strategy" is the right approach, it probably depends on more context than can realistically be shared in a Stack Overflow question. But, taking a step back, the Haskell type system is useful to the extent that it helps clearly model the problem domain. At its best, the types feel natural and assist you with writing correct code. When they stop doing this, you need to rethink your types.
The pain you encountered with a more traditional ADT-driven approach to this problem (rigidity of the types, proliferation of Maybes, and the "tyranny of small differences") suggests that these types were a bad model at least for what you were trying to do in this case. In particular, given that your problem was one of generating fairly straightforward JSON directives/commands for an external API, rather than doing lots of data manipulation on structures that also happened to allow JSON serialization/deserialization, modeling the data as Haskell ADTs was probably overkill.
My best guess is that, if you really wanted to properly model the FB Workplace API, you wouldn't want to do it at the JSON level. Instead, you'd do it at a higher level of abstraction with Message, Comment, and Group types, and you'd end up wanting to generate the JSON dynamically anyway, because your types wouldn't directly map to the JSON structures expected by the API.
It might be insightful to compare your problem to generating HTML. Consider first the lucid (blaze-based) or shakespeare templating packages. If you look at how these work, they don't try to build up HTML by generating a DOM with ADTs like data Element = ImgElement ... | BlockquoteElement ... and then serializing them to HTML. Presumably the authors decided that this abstraction wasn't really necessary, because the HTML just needs to be generated, not analyzed. Instead they use functions (lucid) or a quasiquoter (shakespeare) to build up a dynamic data structure representing an HTML document. The chosen structure is rigid enough to ensure certain sorts of validity (e.g., proper matching of opening and closing element tags) but not others (e.g., no one stops you from sticking a <p> child in the middle of your <span> element).
When you use these packages in a larger web app, you model the problem domain at a higher level of abstraction than HTML elements, and you generate the HTML in a largely dynamic fashion because there's not a clear one-to-one mapping between the types in your problem domain model and HTML elements.
On the other hand, there's a type-of-html package that does model individual elements, so it's a type error to try to nest a <tr> inside <td> and so on. Developing these types probably took a lot of work, and there's a lot of inflexibility "baked in", but the trade-off is a whole other level of type safety. On the other hand, this seems easier to do for HTML than to do for a particular finicky JSON API.
I've got JSON file that looks like this
{
"alliance":{
"name_part_1":[
"Ab",
"Aen",
"Zancl"
],
"name_part_2":[
"aca",
"acia",
"ythrae",
"ytos"
],
"name_part_3":[
"Alliance",
"Bond"
]
}
}
I want to store it in dynamoDB.
The thing is that I want a generator that would take random elements from fields like name_part_1, name_part_2 and others (number of name_parts_x is unlimited and overalls number of items in each parts might be several hundreds) and join them to create a complete word. Like
name_part_1[1] + name_part_2[10] + name_part[3]
My question is that what format I should use to do that effectively? Or NoSQL shouldn't be used for that? Should I refactor JSON for something like
{
"name": "alliance",
"parts": [ "name_part_1", "name_part_2", "name_part_3" ],
"values": [
{ "name_part_1" : [ "Ab ... ] }, { "name_part_2": [ "aca" ... ] }
]
}
This is a perfect use case for DynamoDB.
You can structure like this,
NameParts (Table)
namepart (partition key)
range (hash key)
namepart: name_part_1 range: 0 value: "Ab"
This way each name_part will have its own range and scalable. You can extend it to thousands or even millions.
You can do a batch getitem from the sdk of your choice and join those values.
REST API reference:
https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html
Hope it helps.
You can just put the whole document as it is in DynamoDB and then use document path to access the elements you want.
Document Paths
In an expression, you use a document path to tell DynamoDB where to
find an attribute. For a top-level attribute, the document path is
simply the attribute name. For a nested attribute, you construct the
document path using dereference operators.
The following are some examples of document paths. (Refer to the item
shown in Specifying Item Attributes.)
A top-level scalar attribute: ProductDescription A top-level list
attribute. (This will return the entire list, not just some of the
elements.) RelatedItems The third element from the RelatedItems list.
(Remember that list elements are zero-based.) RelatedItems[2] The
front-view picture of the product. Pictures.FrontView All of the
five-star reviews. ProductReviews.FiveStar The first of the five-star
reviews. ProductReviews.FiveStar[0] Note The maximum depth for a
document path is 32. Therefore, the number of dereferences operators
in a path cannot exceed this limit.
Note that each document requires a unique Partition Key.
Im new to angularJS and web designing as a whole. Im trying to get a data field(or element) from a JSON. For example, this is what the JSON looks like
{
"Name":"Raymond Eugene Monce",
"Dateofbirth":"1924-0308T00:00:00Z",
"Ethnicity":"Caucasian",
"Languages":["{English}"],
},
and I'm trying to get the "Name" data field. This is what my .js file looks like,
var profile = angular.module('profile', ['ui.bootstrap','ngResource']);
profile.controller("profileController", ["$scope","$resource", function($scope, $resource) {
// get the user id
$scope.userid = sessionStorage["cerestiuserid"];
// json we get from server
$scope.apicall = sessionStorage["cerestihome"]; // NEED TO CHANGE API
// grabs the user we want
$scope.userResource = $resource($scope.apicall + "/api/userprofile/",
{Userid:21},
{'get':{method: 'POST'}}
);
// fetch JSON
$scope.userResource.get(function(result) {
// get the name field
$scope.name = result;
sessionStorage["name"] = JSON.stringify(result);
});
and my .html file,
<div ng-controller = "profileController" style="float:left">
<!-- profile pic -->
<div class="pull-left">
<div class="container-fluid">
<div class="profile">
<div class="row">
<div class="center-block">
<div class="profilePic">
<img ng-src="{{profilePic()}}" class="img-responsive">
<!-- name field -->
<label class="caption">
<h4>{{name.name}}</h4>
</label>
</div>
Again, Im not having problems with the Database or API calls. I just want to know how I can get and display the name field of the JSON. Thanks.
strelok2010's comment above should work although that depends on if your result really looks like the one defined at the top of your question.
Your result seems to be a normal javascript object not JSON. (yeah they are different, and that confused me when I learned it.) I assume that because you stringify the result from a javascript object into JSON. Therefore if that is working right your result is either a javascript object or an array of javascript objects. I'm assuming an array. You might want to check though.
I noticed your earlier post had a related problem.
In that one you were asking to access a property of an object that was in an array. In that case it was result as well. Here was the answer from your previous question
var result = [{"name": "Jason"
"date of birth": "february 23, 2985"
....
}];
var firstResultsName = result[0].name;
There are two things I am unsure of due to the inconsistency between this and your last question.
First your name property in your results object is spelled with a capital N here as opposed to a lower case n in your last question.
Keep in mind that capitilization matters in javascript.
Second your result in your last question was an array of objects and in this it seems to be just an object.
So depending on which one it is will determine your solution. So instead of writing every possible solution I'll show you how to determine the solution.
Remember we are dealing with a normal array of javascript objects. I'll try to go into detail so it's extra clear (sorry I heard you were new to web developement, I'm assuming JavaScript too.), but sorry if it's a little too detailed. I will also be breaking it into parts to go deeper into the array of objects that I'll use in my example, but traversing into the data structure can all be done in a single line as I will show.
You can only do actions on the 'outermost-form' (by the way 'outermost-form' is just a term I'll use for clarification it's not really a technical term.) and work your way into the collection (object/array/string)
As an example we have an array of people, with the array being the 'outermost-form'
var people = [
{
"name": "Bob",
"occupation": "Architect",
"date of birth": "01/23/83"
},
{
"name": "Timothy",
"Occupation": "Accountant",
"date of birth": "02/23/78"
}
];
If we saw the value of people at this moment it not surprisingly be.
[
{
"name": "Bob",
"occupation": "Architect",
"date of birth": "01/23/83"
},
{
"name": "Timothy",
"Occupation": "Accountant",
"date of birth": "02/23/78"
}
]
Start with the Array
Since it's an array as the 'outermost-form' we can get one of its values using an index. Just like any other array. Just for a bit of contrast I'll show you how what we are doing is similar to any other array by showing an example of an array by itself
// simple array example
var array = ["foo", "bar", "baz"];
array[0] // returns "foo"
// more simple array example, but less practical (it's more just for showing how javascript can work.)
["foo", "bar", "baz"][2] // returns "baz"
Back to our main example. Let's make a variable person and store our first person in the people array in that value.
var person = people[0];
Now if saw our person variable it would equal the following
{
"name": "Bob",
"occupation": "Architect",
"date of birth": "01/23/83"
}
You can see just like the normal array it grabs the first item in the array. You can see how we are slowly traversing into our people data structure. (that being an array of objects.)
Enter the Object
Okay so now we have the person object, but we want the name of that person so since we are dealing with an object we have to access its properties we can do this with either 'dot notation', e.g. <object>.<property>, or 'bracket notation' which can be done with either a variable or a string for the property name. e.g. <object>.["<property>"] or <object>.[<variable>]
So just as a side example I will show you what it normally takes to get the value of a property of an object just so you can compare and see there's no 'magic' going on. Keep in mind javascript is case-sensitive. Also javascript objects properties can go with or without surrounding quotes unlike JSON. One last thing having a space in the property name forces us to use quotes, and also forces us to access that property via bracket notation.
var result;
var obj = { foo: 1, Bar: 2, "foo bar": 3 };
var randomVarName = "Bar"; // notice the capital B in Bar is important since it was declared that way.
result = obj.foo; // result equals 1
result = obj[randomVarName]; // result equals 2
result = obj["foo bar"]; // result equals 3
Back again to our main train of thought. So we have traversed into our people array to find the person object now let's get their name.
var name = person.name;
The value of name would be.
"Bob"
You can do with that what you wish. You could have also used any of the previous ways to get an objects property including bracket notation.
Do Everything we just did in a Single Line
So to write that all in one line you would just write
people[0].name
Apply to your Question
So to apply to your question if your result looks like this
var result = [
{
"name": "Jason"
"date of birth": "february 23, 2985"
....
}
];
Then you need this to get the name
result[0].name
If it's just this
var result = {
"name": "Jason"
"date of birth": "february 23, 2985"
....
}
Then you just need
result.name
As asked in the comment if you want to get the date of birth property out of the object you need to use bracket notation to get the element out of an object. Bracket notation is one of the two object property accessors the other being dot notation. I covered both at the enter the object section. It can be used at anytime, but is usable in some cases that dot notation does not work.
An example and quote from MDN:
get = object[property_name];
object[property_name] = set;
property_name is a string. The string does not have to be a valid identifier; > it can have any value, e.g. "1foo", "!bar!", or even " " (a space).
So since certain character like spaces can't be used in dot notation bracket notation must be used in those special cases when those characters are present.
Below is the bracket notation of the date of birth.
result["date of birth"]
Like I said before it can be used anywhere, but generally dot notation is preferred for its brevity. So just to show that, we will show the name field being accessed using bracket notation:
result["name"]
One additional reason you may want to use bracket notation is for its ability to use variables like so.
var prop_name = "date of birth";
result[prop_name];
which actually if you understand the principle of that example the MDN example might make more sense.
If you have a question feel free to leave me a comment.
Is it a good practice storing related information in the HTML tag?
$("#my_div").append("<span id='info' boo='foo'/>");
$("#info").attr("boo");
I've encountered with such technique (and slightly borrowed it) in TAL (in ZPT) where you could use tal:attributes statement to modify HTML tags (e.g. passing the value of boo variable from backend to be rendered in the final document as attribute value):
<span id='info' tal:attributes='boo view/boo'>
result:
<span id='info' boo='foo'>
Will this technique break a document someday, or it is safe by the spec?
The right way to do it is to use data-* attributes:
http://www.w3.org/TR/2011/WD-html5-20110525/elements.html#embedding-custom-non-visible-data-with-the-data-attributes
Tangentially, jQuery has a special method for working with these as well. For example:
<p id='string' data-user_name='thedude'></p>
$('#string').data('user_name') => "thedude"
typeof $('#string').data('name') => "string"
<p id='number' data-user_id='12345'</p>
typeof $('#number').data('user_id') => "number"
<p id='boolean' data-user_is_active='true'></p>
typeof $('#boolean').data('user_is_active') => "boolean"
<p id = 'json' data-user='{"name": "the dude", "id": "12345"}'></p>
typeof $('#json').data('user') => "object"
// embedding JSON is extremely useful in my experience
w3.org allows in HTML5 to use user custom data in html tags;
See the section:
3.2.3.9 Embedding custom non-visible data with the data-* attributes
A custom data attribute is an attribute in no namespace whose name
starts with the string "data-", has at least one character after the
hyphen [...]
Example:
<ol>
<li data-length="2m11s">Beyond The Sea</li>
...
</ol>
So, I'll say that it is a accepted practice for HTML5.