1

I'm going to use various data attributes names start with for example "data-mo-".

Assume I have these elements:

<span data-mo-top-fade-duration="600">Title 1</span>
<span data-mo-bottom-fade-duration="600">Title 2</span>
<span data-mo-right-fade-duration="600">Title 3</span>
<span data-mo-left-fade-duration="600">Title 4</span>

I know how to handle elements whose data attribute values start with some value, but how can it be done for the data attribute names?

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
Morad Hamdy
  • 115
  • 1
  • 11
  • 2
    Great, Where is your code? – Sudharsan S Aug 29 '16 at 13:12
  • Please post the code you have tried so far. – Umair Farooq Aug 29 '16 at 13:15
  • You didn't get the idea?! @SudharsanS .. Wait. – Morad Hamdy Aug 29 '16 at 13:15
  • 2
    Possible duplicate of [jQuery - How to select value by attribute name starts with](http://stackoverflow.com/questions/26657398/jquery-how-to-select-value-by-attribute-name-starts-with) – depperm Aug 29 '16 at 13:15
  • 1
    Question updated.. – Morad Hamdy Aug 29 '16 at 13:19
  • It is much better, for easy accessing, to use same class on those elements or to add one more attribute as `data-mo` for all. Better for CSS and JS. For example: `` or ``. – skobaljic Aug 29 '16 at 13:24
  • Your question is confusing - but I think that's because you're struggling a little with the English language, which I can certainly understand - however, I *think* you're asking either **1:** how can I select all elements that have a `data-*` attribute that starts with `data-mo`, or **2:** how to check if the current element has a `data-attribute` that starts with `data-mo`? Can you clarify which? Or, if it's something else entirely, can you try to rephrase your question more clearly, perhaps have a friend review the question to help you? – David Thomas Aug 29 '16 at 13:25
  • The 2nd @DavidThomas – Morad Hamdy Aug 29 '16 at 13:26

3 Answers3

3

If all you wish to do is find whether a given node has an attribute beginning with a specific string, then one approach is the following:

// node: a single HTMLELement node,
// attr: the string to test against the attribute names:
function hasAttributeStartingWith(node, attr) {

  // here we return the result, using Array.from() to turn
  // the node-map of attributes into an Array, and then
  // Array.prototype.filter() to remove any attributes that
  // do not return a true/truthy result against the supplied
  // assessment:
  return Array.from(node.attributes).filter(function(attributeNode) {
    // attributeNode: a reference to the current attribute-node
    // of the array of attribute-nodes over which we're iterating.

    // here we test to see if the nodeName (the attribute-name)
    // of the attribute-node begins with  the supplied string
    // (held in the 'attr' variable):
    return attributeNode.nodeName.indexOf(attr) === 0;

  // if the filtered array is greater than zero then
  // there are some attributes beginning with the
  // supplied string:
  }).length > 0;
}

// here we convert the nodeList returned from document.querySelectorAll()
// into an Array, using Array.from(), and iterate over those elements
// using Array.prototype.forEach():
Array.from(document.querySelectorAll('span')).forEach(function(span) {
  // 'span': a reference to the current <span> element of the
  // array of <span> elements over which we're iterating.

  // using the function within the 'if' assessment, since it
  // returns a Boolean true/false:
  if (hasAttributeStartingWith(span, 'data-mo')) {

    // using the Element.classList API to add
    // the 'hasAttributeStartingWith' class to
    // the current <span> if the function returns
    // true:
    span.classList.add('hasAttributeStartingWith');
  }

});

function hasAttributeStartingWith(node, attr) {
  return Array.from(node.attributes).filter(function(attributeNode) {
    return attributeNode.nodeName.indexOf(attr) === 0;
  }).length > 0;
}

Array.from(document.querySelectorAll('span')).forEach(function(span) {
  if (hasAttributeStartingWith(span, 'data-mo')) {
    span.classList.add('hasAttributeStartingWith');
  }
});
.hasAttributeStartingWith {
  display: inline-block;
  font-size: 1.5em;
  color: limegreen;
}
<span data-mo-top-fade-duration="600">Title 1</span>
<span data-mo-bottom-fade-duration="600">Title 2</span>
<span data-mo-right-fade-duration="600">Title 3</span>
<span data-mo-left-fade-duration="600">Title 4</span>

JS Fiddle demo.

In the above all elements have an attribute starting with data-mo, to show it working more specifically, try:

Array.from(document.querySelectorAll('span')).forEach(function(span) {
  if (hasAttributeStartingWith(span, 'data-mo-b')) {
    span.classList.add('hasAttributeStartingWith');
  }
});

function hasAttributeStartingWith(node, attr) {
  return Array.from(node.attributes).filter(function(attributeNode) {
    return attributeNode.nodeName.indexOf(attr) === 0;
  }).length > 0;
}

Array.from(document.querySelectorAll('span')).forEach(function(span) {
  if (hasAttributeStartingWith(span, 'data-mo-b')) {
    span.classList.add('hasAttributeStartingWith');
  }
});
.hasAttributeStartingWith {
  display: inline-block;
  font-size: 1.5em;
  color: limegreen;
}
<span data-mo-top-fade-duration="600">Title 1</span>
<span data-mo-bottom-fade-duration="600">Title 2</span>
<span data-mo-right-fade-duration="600">Title 3</span>
<span data-mo-left-fade-duration="600">Title 4</span>

JS Fiddle demo.

This should match only the element which has an attribute starting with the string data-mo-b, styling only the second <span> element.

References:

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • `array.some(f)` should be more efficient than `array.filter(f).length > 0`. Also, `string.startsWith("something")` instead of `string.indexOf("something") === 0`. (Maybe even `[].some.call(node.attributes, f)` if that works; not tested.) – Dogbert Aug 29 '16 at 15:40
1

A concise approach using ES6 is to select all elements in the document, then .filter by whether .some of the attribute names start with the string you're looking for:

const moElements = [...document.querySelectorAll('*')]
  .filter(elm => [...elm.attributes].some(
    ({ name }) => name.startsWith('data-mo-')
  ));
console.log(moElements);
<span data-mo-top-fade-duration="600">Title 1</span>
<span data-mo-bottom-fade-duration="600">Title 2</span>
<span data-mo-right-fade-duration="600">Title 3</span>
<span data-mo-left-fade-duration="600">Title 4</span>
<span>somethingElse</span>

Or, if you want to avoid constructing the intermediate arrays with spread, you can .call the array methods on the element / attribute collections instead:

const moElements = Array.prototype.filter.call(
  document.querySelectorAll('*'),
  elm => Array.prototype.some.call(
    elm.attributes,
    ({ name }) => name.startsWith('data-mo-')
  )
);
console.log(moElements);
<span data-mo-top-fade-duration="600">Title 1</span>
<span data-mo-bottom-fade-duration="600">Title 2</span>
<span data-mo-right-fade-duration="600">Title 3</span>
<span data-mo-left-fade-duration="600">Title 4</span>
<span>somethingElse</span>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

If I get it right you want to check for data-mo so I have tried something to make this work;

function getData(index){
 if(index[0].indexOf("mo") !== -1)
     return true
        
    return false
}

$.each($("span"), function(i,index){
 var objectKey = Object.keys($(this).data());
 if(getData(objectKey)){
     $(this).addClass("valid")
    } else {
     $(this).addClass("not-valid")
    }
     
})
.valid {
    color: green
}
.not-valid {
    font-weight: bold;
    color: red;
    text-decoration: line-through
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span data-mo-top-fade-duration="600">Title 1</span>
    <span data-mo-bottom-fade-duration="600">Title 2</span>
    <span data-mo-right-fade-duration="600">Title 3</span>
    <span data-mo-left-fade-duration="600">Title 4</span>
    <span data-not-valid-one-left-fade-duration="600">Title 5</span>
Hakan Kose
  • 1,649
  • 9
  • 16