I have a directive in an ng-repeat loop. I need to set a flag that each instance of the directive can access and change.
<div class="form-group">
<form-builder ng-repeat="fl in t.fieldList"></form-builder>
</div>
So as an example, myFlag in this directive would persist:
angular.module('app').directive("formBuilder", function ($compile) {
return {
replace: true,
link: function (scope, element, attrs) {
myFlag = (myFlag === 'start') ? 'end' : 'start';
angular.element(element.append($compile("<div>" + myFlag + "</div>")(scope)));
}
};
});
And the output would be:
start
end
start
end
...
How do I persist myFlag between directive instances?
(Yes, I know that myFlag isn't defined or stored anywhere... that's what I'm asking to do...)
Related
I am having a node type with machine name to_do_item, and I want to create a module called managefinishdate to update the node: when a user edit the node's field (field_status) to "completed" and click "save", then the module will auto update the field_date_finished to current date.
I have tried to create the module and already success to install in "Extend":
function managefinishdate_todolist_update(\Drupal\Core\Entity\EntityInterface $entity) {
...
}
however, I am not sure is this module being called, because whatever I echo inside, seems nothing appeared.
<?php
use Drupal\Core\Entity\EntityInterface;
use Drupal\node\Entity\Node;
/** * Implements hook_ENTITY_TYPE_update().
* If a user update status to Completed,
* update the finished date as save date
*/
function managefinishdate_todolist_update(\Drupal\Core\Entity\EntityInterface $entity) {
$node = \Drupal::routeMatch()->getParameter('node');
print_r($node);
//$entity_type = 'node';
//$bundles = ['to_do_item'];
//$fld_finishdate = 'field_date_finished';
//if ($entity->getEntityTypeId() != $entity_type || !in_array($entity->bundle(), $bundles)) {
//return;
//}
//$current_date=date("Y-m-d");
//$entity->{$fld_finishdate}->setValue($current_date);
}
Following Drupal convention, your module named 'manage_finish_date' should contain a 'manage_finish_date.module file that sits in the root directory that should look like this:
<?php
use Drupal\node\Entity\Node;
/**
* Implements hook_ENTITY_TYPE_insert().
*/
function manage_finish_date_node_insert(Node $node) {
ManageFinishDate::update_time();
}
/**
* Implements hook_ENTITY_TYPE_update().
*/
function manage_finish_date_node_update(Node $node) {
ManageFinishDate::update_time();
}
You should also have another file called 'src/ManageFinishDate.php' that should look like this:
<?php
namespace Drupal\manage_finish_date;
use Drupal;
use Drupal\node\Entity\Node;
class ManageFinishDate {
public static function update_time($node, $action = 'create') {
// Entity bundles to act on
$bundles = array('to_do_item');
if (in_array($node->bundle(), $bundles)) {
// Load the node and update
$status = $node->field_status->value;
$node_to_update = Node::load($node);
if ($status == 'completed') {
$request_time = Drupal::time();
$node_to_update->set('field_date_finished', $request_time);
$node_to_update->save();
}
}
}
}
The code is untested, but should work. Make sure that the module name, and namespace match as well as the class filename and class name match for it to work. Also, clear you cache once uploaded.
This will handle newly created and updated nodes alike.
Please look after this sample code which may help you:
function YOUR_MODULE_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
switch ($entity->bundle()) {
//Replace CONTENT_TYPE with your actual content type
case 'CONTENT_TYPE':
$node = \Drupal::routeMatch()->getParameter('node');
if ($node instanceof \Drupal\node\NodeInterface) {
// Set the current date
}
break;
}
}
I'm building a utility into a style guide generator that automatically gathers the CSS for each element and displays it adjacent to the element in the output. The script I'm using to gather and parse the CSS is based on an answer from SO and uses the element.matches() web API.
Under most circumstances the code works perfectly, but in cases where there is a 'vendor prefix'-specific pseudo-element selector (e.g. ::-webkit-inner-spin-button as in Bootstrap 4.0), Safari throws an error at the most nested if statement (i.e. if (a.matches(rules[r].selectorText)) {):
SyntaxError (DOM Exception 12): The string did not match the expected pattern.
I've tried searching for this error specifically on SO and I found this question that talks about missing array endings, but I don't think the answer pertains to my issue.
I have a regex workaround that will remove the offending rules so the function can at least run, but as you can see, the properties in that rule ({background-color:black;}) are completely ignored in the output even though they're applied to the rendered element.
I could modify my regex to parse the strings and slice out problematic selectors while leaving the parsable rules, but overall this type of very specific hack feels inelegant to me, and I'm concerned it may cause problems down the road if my team ends up adding rules that rely on those types of vendor-prefixed pseudo-selectors.
Any ideas on how I can be a little more precise about working around (or solving) this issue?
Working Snippet
window.css = function (a) {
var sheets = document.styleSheets, o = [];
a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector;
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
if (a.matches(rules[r].selectorText)) {
o.push(rules[r].cssText);
}
}
}
return o;
}
$(document).ready(function(){
$('button').on('click',function(){
$('#styles').text(css( $( $('input').val() )[0] ));
});
});
div * {border-left:2px solid black;margin:1em 0;padding:.5em;}
a {text-decoration:none;display:block;cursor:pointer;}
#red {color:red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="#red"><button>Get styles</button>
<div>
<a id="red">#red anchor</a>
</div>
<aside id="styles"></aside>
Broken Snippet
(only change is 1 added line of CSS)
window.css = function (a) {
var sheets = document.styleSheets, o = [];
a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector;
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
if (a.matches(rules[r].selectorText)) {
o.push(rules[r].cssText);
}
}
}
return o;
}
$(document).ready(function(){
$('button').on('click',function(){
$('#styles').text(css( $( $('input').val() )[0] ));
});
});
div * {border-left:2px solid black;margin:1em 0;padding:.5em;}
a {text-decoration:none;display:block;cursor:pointer;}
#red {color:red;}
/* v ADDED THIS LINE - THIS IS THE ONLY CHANGE v */
[type="submit"]::-webkit-inner-spin-button {background-color:black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="#red"><button>Get styles</button>
<div>
<a id="red">#red anchor</a>
</div>
<aside id="styles"></aside>
Reg-Ex Workaround
window.css = function (a) {
var sheets = document.styleSheets, o = [];
a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector;
// v NEW FUNCTION v
function removeVendorPrefixSelectors (selectorText) {
if (/::-/.test(selectorText)) {
//do nothing
} else {
return selectorText;
}
}
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
// v NEW LINE v
rule = removeVendorPrefixSelectors(rules[r].selectorText);
if (a.matches(rule)) {
o.push(rules[r].cssText);
}
}
}
return o;
}
$(document).ready(function(){
$('button').on('click',function(){
$('#styles').text(css( $( $('input').val() )[0] ));
});
});
div * {border-left:2px solid black;margin:1em 0;padding:.5em;}
a {text-decoration:none;display:block;cursor:pointer;}
#red {color:red;}
a, [type="submit"]::-webkit-inner-spin-button {background-color:black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="#red"><button>Get styles</button>
<div>
<a id="red">#red anchor</a>
</div>
<aside id="styles"></aside>
Here I am filling the localStorage:
let storageObj = {};
storageObj.date = (new Date().toLocaleString().replace(", ","T"));
storageObj.url = this.responseURL;
localStorage.setItem(storageObj.date, storageObj.url);
In mounted() I am iterate all data from localStorage like:
for(let obj of Object.entries(localStorage))
{
this.lastpasts.push(obj);
}
And placing every Object to lastpasts (located in data() {lastpasts : []}).
In template I want to print only url:
<div class="ui divided items" v-for="el in lastpasts">
<div class="item">
{{el.url}}
</div>
</div>
But this code do not print nothing. Work only {{el}}. It's print in HTML block:
[ "24.06.2017T11:55:10", "362e9cc5-e7e6" ]
[ "24.06.2017T12:26:47", "b0f9f20d-7851" ]
Browser console do not have any errors.
In the chat session we managed to solve his issue.
It was caused by the fact, that he was using Array of Arrays instead of Array of Objects. Because Array can be used only with index, not field name, {{el.url}} was not working.
The code to get values from LocalStorage had to be changed to:
mounted() {
for(let obj of Object.entries(localStorage)) {
var x = {};
x.url = obj[0];
x.date = obj[1];
this.lastpasts.push(x);
}
}
Now, it is possible to use {{el.url}}
I wander if in foundation 6 sliders, it is possible to allow negative values e.g. swinging from -50 to 50.
Currently I have a slider in [0 100]:
<div class="row">
<div class="small-4 large-4 columns">
<label>Audio Volume</label>
</div>
<div class="small-6 large-6 columns">
<div class="slider" id="slidervol" data-slider data-end="100" display_selector: "#slidervol">
<span class="slider-handle" data-slider-handle role="slider" tabindex="1" aria-controls="sliderVolOutput"></span>
<span class="slider-fill" data-slider-fill></span>
</div>
</div>
<div class="small-2 large-2 columns">
<input name="AudioVolTxtbox" type="number" style="width: 4em;" tabindex="2" id="sliderVolOutput">
</div>
</div>
You can set a negative start value, but the behaviour is unpredictable when you do so. If you want to make use of negative values, you'll need logic to update the value in #sliderVolOutput after the handle has been moved.
The moved.zf.slider event is triggered every time the handle is moved and you can use that fact to update the textbox value. This event is fired quite a few times, so you'll need to add additional code to get rid of the flickering (if it's bothersome).
I've provided some basic code that should get you started. If you have any questions, please let me know.
var target = document.getElementById("slidervol");
var options = {
"start": 0,
"end": 100,
"decimal": 0
};
var elem = new Foundation.Slider($(target), options);
var offset = 50;
$(target).on('moved.zf.slider', function() {
$('#sliderVolOutput').val(Number($('.slider-handle').attr('aria-valuenow')) - offset);
});
Another approach would be to use the mousemove.zf.slider event. This gets rid of the flicker, but the textbox value is only updated once you've stopped manipulating the slider:
$(target).on('mousemove.zf.slider', function() {
$('#sliderVolOutput').val(Number($('.slider-handle').attr('aria-valuenow')) - offset);
});
UPDATE:
In response to your additional query, I've had time to implement the required functionality (editing the value in the text box causing the slider to update) using a hidden control.
The slider-handle now targets the hidden control (aria-controls), which will always contain a positive value. The text box will contain the negative (computed) value. This is what the updated html looks like for the slider-handle:
<span class="slider-handle" data-slider-handle role="slider" tabindex="1" aria-controls="sliderVolOutputHidden"></span>
And this is the additional hidden input I've used:
<input type="hidden" id="sliderVolOutputHidden" value="0">
I've also added an input event for #sliderVolOutput that updates the value of the hidden input and triggers the change event. The change event is important, as without it, the handle will not update:
$('#sliderVolOutput').on('input', function() {
$('#sliderVolOutputHidden').val(Number($('#sliderVolOutput').val()) + offset);
$('#sliderVolOutputHidden').trigger('change');
});
Fiddle Demo
I get quite a result patching as follows foundation.js.
I can change values smoothly with the slider (with no flickering) but I can not decrement the textbox (aria-controls) below 0 since he event handler does not fire.
## -6953,13 +6953,14 ##
'id': id,
'max': this.options.end,
'min': this.options.start,
+ 'offset': this.options.offset,
'step': this.options.step
});
this.handles.eq(idx).attr({
'role': 'slider',
'aria-controls': id,
- 'aria-valuemax': this.options.end,
- 'aria-valuemin': this.options.start,
+ 'aria-valuemax': this.options.end + this.options.offset,
+ 'aria-valuemin': this.options.start + this.options.offset,
'aria-valuenow': idx === 0 ? this.options.initialStart : this.options.initialEnd,
'aria-orientation': this.options.vertical ? 'vertical' : 'horizontal',
'tabindex': 0
## -6978,8 +6979,8 ##
key: '_setValues',
value: function _setValues($handle, val) {
var idx = this.options.doubleSided ? this.handles.index($handle) : 0;
- this.inputs.eq(idx).val(val);
- $handle.attr('aria-valuenow', val);
+ this.inputs.eq(idx).val(val+this.options.offset);
+ $handle.attr('aria-valuenow', val+this.options.offset);
}
/**
## -7033,7 +7034,8 ##
} else {
//change event on input
value = this._adjustValue(null, val);
- hasVal = true;
+ value = value - this.options.offset;
+ hasVal = true;
}
this._setHandlePos($handle, value, hasVal);
## -7286,7 +7288,13 ##
* #option
* #example false
*/
- invertVertical: false
+ invertVertical: false,
+ /**
+ *
+ * #option
+ * #example 0
+ */
+ offset: 0
};
function percent(frac, num) {
Then, for instance I want to change my parameter "Audio Volume" from -24 to 24 so in js:
// Audio Volume
vartxt = GetParameter("AudioVolume") // get the value in some way
tval = parseFloat(vartxt);
document.DeviceConfig.AudioVolTxtbox.value = tval - 24; //change the textbox
var target = document.getElementById("slidervol");
var options = {
"start": 0,
"end": 48,
"decimal": 0,
"step": 1,
"offset": -24,
"initialStart": tval
};
var elem = new Foundation.Slider($(target), options);
At the moment the only problem I get is that I have to configure the input box as 'text', since if I set it as 'number' the spinner does not allow to go below the 0.
In my PHP error handler I want to do something like:
if (ini_get('display_errors') IS ON)) {
// show debug info
} else {
// show just "oops!"
}
I've look through the docs and stuff, but I can't really find out what the possible values for display_errors are (such as "on", 0, "Yes") and what it does for what value.
What should I put in place of the "IS ON" to reliably read this value?
I use the following code:
if (in_array(strtolower(ini_get('display_errors')), ['1', 'yes', 'on', 'true']) {
// is enabled
} else {
// is disabled
}
Or regexp
if (preg_match('/^(1|yes|on|true)$/i', ini_get('display_errors')) {
// is enabled
} else {
// is disabled
}
You can get the string representation of the values through ini_get(), values that display_errors can be set to is either, true\false, 0\1 and On\Off. But when user's set their php.ini it is more common to use 1 or On
if (ini_get('display_errors') == "1") {
// show debug info
}
or to check for ALL cases, you can perform a switch-case
ini_set('display_errors', 1);
switch (ini_get('display_errors')) {
case "1":
case "On":
case "true":
// show debug info
}
If you prefer the equality comparison approach, notice that ini_get returns a String value of 1, if you test the returned value with ini_get using the == with the int value 1, it becomes true. If you use the === it checks if both are equal and of the same type. String is not the same type as int so it would return false.
1 == "1"; // in PHP, this returns true, it doesn't check the type.
1 === "1"; // would be false, this however checks the type.
Using ini_get('display_errors') you can check against values like, TRUE, FALSE, and
even NULL. They will return a boolean value of either 0 which is false and anything other than 0 evaluates to true.
if (2) {
echo "2 is true!"; // echos "2 is true!"
}
I saw your comment about a discrepancy so I decided to test it myself, here is what I used
<?php
ini_set('display_errors', 1);
$verbose = ini_get('display_errors');
echo $verbose; // echo's 1
// just to test its return values.
if ($verbose) {
echo "verbose is true"; // echos "verbose is true"
}
ini_set('display_errors', 0);
$verbose = ini_get('display_errors');
echo $verbose; // echo's 0
if ($verbose) {
echo "verbose is not true"; // does not get evaluated
}
?>
This answer is a bit lengthy, but I hope this is what you need.
Use filter_var
if ( filter_var( ini_get('display_errors'), FILTER_VALIDATE_BOOLEAN) ){
}
And that should catch all of the different ways display_errors could get turned on ("1", "true", "on", "yes", etc.).
I also can't find any official documentation on this, but from what I've experienced, I believe using filter_var with the FILTER_VALIDATE_BOOLEAN flag will cover the full gamut of possible ways an ini setting can be set to true/false.
The default is '1' according to the documentation. However, you might want to check the inverse, that it isn't off:
!= FALSE or !empty()
if (ini_get('display_errors') != FALSE))
{
// show debug info
}
else
{
// show just "oops!"
}
Or as Anthony pointed out, you could just check for 1
if(ini_get('display_errors') == 1))
You might also want to check error_reporting, as it is another common setting that is used to control the displaying of errors, although its meaning is slightly different than display_errors
if(error_reporting() != 0)