How to use indexof on array derbyjs - derbyjs

I have an array passed to my template and I want to see if I have the value stored in it:
{{each _page.friends as #friend}}
{{if _page.user.friends.indexOf(#friend.id)<0}}
<button>Add</button>
{{else}}
Already Friends
{{/if}}
{{/each}}
Apparently indexOf isn't a function, but the array (_page.user.friends) does seem to exist I can use it its own {{each}}....
Is there a way to do this? Or perhaps a better way?

I do not see support for indexOf mentioned in Derby View documentation. However, you can always use a view function to determine whether someone is a friend or not.
// in the view
{{each _page.friends as #friend}}
{{if isFriend(_page.user.friends, #friend.id)}}
<button>Add</button>
{{else}}
Already Friends
{{/if}}
{{/each}}
// in controller
FriendListController.prototype.isFriend = function(friends, friendId) {
return friends.indexOf(friendId) > 0;
};

Related

How to get reactive validation with array group?

I have set code this way
errorGroup: any = FormGroup;
this.errorGroup = this.formBuilder.group({
errors: this.formBuilder.array([])
});
For repeat/add new data in group I have add this function which works fine.
addErrorGroup() {
return this.formBuilder.group({
error_code: ['',[Validators.required ]]
})
}
Get controls by this way. I think hear I'm missing something.
get f() { return this.errorGroup.controls.errors; }
In HTML
<select formControlName="error_code" name="error_code" (change)="errorCodeChange($event.target.value , i)">
<option *ngFor="..." value={{...}}>{{...}}</option>
</select>
<span *ngIf="f.error_code.errors.required" class="error-msg">This is required field.</span>
I got this error.
ERROR TypeError: Cannot read property 'errors' of undefined
If that error is coming from HTML, it's because your *ngIf condition is trying to read a value from an undefined object.
At the point where the view is rendered, and checked, it's entirely possible that f (incidentally, you should change that variable name to something more descriptive, but 🤷🏻‍♂️) doesn't have any errors populated yet, so will be undefined.
You can do one of two things here, either, you can wrap the whole thing in another *ngIf to ensure the error_code part of f is populate before accessing it:
<span *ngIf="f && f.error_code">
<span *ngIf="f.error_code.errors.required" class="error-msg">This is required field.</span>
</span>
Or, you can use the safe navigation operator:
<span *ngIf="f?.error_code?.errors?.required" class="error-msg">This is required field.</span>
Note the ? after each object key. This bails out when it hits the first null value, but, the app continues to work as it fails gracefully.
You can read more about it here: https://angular.io/guide/template-syntax#the-safe-navigation-operator----and-null-property-paths
How about if you just do below?
<span *ngIf="errorGroup.get('error_code').errors.required" class="error-msg">
This is required field.
</span>
so by doing this way, you don't need the f() getter in your component file.

Dynamic Vue Form from Input-Elements

I'm building a reusable vue-form-component. For more flexibility the basic idea is to NOT have to specify the form information in the vue-data-object beforehand, but to get the data-structure from the dom-input-elements itself.
On instance-creation the "v-model" attributes are read from the input-tags and applied to the instance via vue.set()
This works fairly well: https://jsfiddle.net/seltsam23/hrL3ec3z/9/
One detail is missing though: I need to only query the children-input-fields, and not the site-wide fields in case I'm using more than one form-component at the same time:
created() {
var inputs = document.querySelectorAll('input'); // works, but this returns ALL elements
var inputs = this.$el.querySelectorAll('input'); // Doesn't work because $el is only available after mounted().
...
}
mounted() {
var inputs = this.$el.querySelectorAll('input'); // works, but attribute "v-model" is removed from inputs at this point
...
}
I've tried to create data-path attribute in the created() phase to store the v-model value on the element itself, but after mount all those created attributes disappear.
Any ideas how to achieve this in an elegant way?
You should be aware that the only reason you see v-model attributes at all is that you're using inline-template. They are in the DOM during the created phase because the template has not yet been processed. What I'm saying is that you're trying to do something pretty hacky, and you probably shouldn't.
It's backward to the normal Vue approach of having the data model drive the DOM, but I know that in some cases it is useful to initialize things from the HTML.
How about this approach?
Vue.component('my-form', {
props: ['init'],
data() {
return {
form: {}
}
},
created() {
this.form = this.init;
}
})
new Vue({
el: '#vue',
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="vue">
<my-form inline-template :init="{foo: {bar: 'one', baz: 'two'}}">
<form>
<input type="text" v-model="form.foo.bar">
<span v-text="form.foo.bar"></span>
<hr>
<input type="text" v-model="form.foo.baz">
<span v-text="form.foo.baz"></span>
</form>
</my-form>
</div>

Current Context for Iron-Router in Templates

So I've got iron-router that returns Posts.find({_id: id}) in it's data function.
Now I'm wondering how I should handle this in the respective template.
My Question: What is the data context for Iron-Router?
In my template I would be doing something like this
{{#each some_context}}
{{content}} <br>
{{/each}}
So what would be the context I should be going with?
In your data function in iron-router do something like this
var return_object = {
all_posts: Posts.find({_id: id})
}
return return_object;
In your html file you can do something like this
<template name="all_posts">
{{#each all_posts}}
{{title}}
{{/each}}
</template>
The router sets the data context to whatever you return in the data function. In this case you've returned return_object so you have access to all of it's fields. Structuring your return like this ensures that you can use the right data context when going through your each.

How to use ng-class in select with ng-options

I have an array of Person objects
var persons = [
{Name:'John',Eligible:true},
{Name:'Mark',Eligible:true},
{Name:'Sam',Eligible:false},
{Name:'Edward',Eligible:false},
{Name:'Michael',Eligible:true}
];
and i am using select with ng-options like this:
<select ng-model="Blah" ng-options="person.Name for person in persons"></select>
I want to show the record with Eligible:false in red color.
So the problem is how do i use the ng-class in select inorder to achieve this? Since we are not using any option tag it wont work if i simply add ng-class in the select element itself.
You could create a directive that processed the options after the ngOptions directive is processed that updated them with the appropriate classes.
Update: The old code had a few bugs, and I've learned a bit since I answered this question. Here is a Plunk that was redone in 1.2.2 (but should work in 1.0.X as well)
Here is updated (Nov 30 '13 at 3:17) the Code:
app.directive('optionsClass', function ($parse) {
return {
require: 'select',
link: function(scope, elem, attrs, ngSelect) {
// get the source for the items array that populates the select.
var optionsSourceStr = attrs.ngOptions.split(' ').pop(),
// use $parse to get a function from the options-class attribute
// that you can use to evaluate later.
getOptionsClass = $parse(attrs.optionsClass);
scope.$watch(optionsSourceStr, function(items) {
// when the options source changes loop through its items.
angular.forEach(items, function(item, index) {
// evaluate against the item to get a mapping object for
// for your classes.
var classes = getOptionsClass(item),
// also get the option you're going to need. This can be found
// by looking for the option with the appropriate index in the
// value attribute.
option = elem.find('option[value=' + index + ']');
// now loop through the key/value pairs in the mapping object
// and apply the classes that evaluated to be truthy.
angular.forEach(classes, function(add, className) {
if(add) {
angular.element(option).addClass(className);
}
});
});
});
}
};
});
Here's how you'd use it in your markup:
<select ng-model="foo" ng-options="x.name for x in items"
options-class="{ 'is-eligible' : eligible, 'not-eligible': !eligible }">
</select>
It works like ng-class does, with the exception that it's on a per-item-in-the-collection basis.
In this scenario you can only apply ng-class only if you use ng-repeat with option tags:
<select ng-model="Blah">
<option ng-repeat="person in persons" ng-class="{red: person.Eligible}">
{{person.Name}}
</option>
</select>
This will give custom class to your 'Eligible' persons, but CSS won't work consistently across bowsers.
Plunker.
I wanted to comment on the accepted answer, but because I don't have enough reputation points, I must add an answer.
I know that this is an old question, but comments where recently added to the accepted answer.
For angularjs 1.4.x the proposed directive must be adapted to get it working again.
Because of the breaking change in ngOptions, the value of the option isn't anymore the index, so the line
option = elem.find('option[value=' + index + ']');
won't work anymore.
If you change the code in the plunker to
<select ng-model="foo" ng-options="x.id as x.name for x in items"
options-class="{ 'is-eligible' : eligible, 'not-eligible': !eligible }">
</select>
As result the value of the option tag will now be
value="number:x" (x is the id of the item object)
Change the directive to
option = elem.find('option[value=\'number:' + item.id + '\']');
to get it working again.
Of course this isn't a generic solution, because what if you have not an id in your object?
Then you will find value="object:y" in your option tag where y is a number generated by angularjs, but with this y you can't map to your items.
Hopes this helps some people to get their code again working after the update of angularjs to 1.4.x
I tried also to use the track by in ng-options, but didn't get it to work.
Maybe people with more experience in angularjs then me (= my first project in angularjs)?
The directive is one way, but I used a custom filter.
If you know how to select your element, you should be fine here. The challenge was to find the current option element inside the select. I could have used the "contains" selector but the text in the options may not be unique for items. To find the option by value, I injected the scope and the item itself.
<select ng-model="foo" ng-options="item.name|addClass:{eligible:item.eligible,className:'eligible',scope:this,item:item} for item in items"></select>
and in the js:
var app = angular.module('test', []);
app.filter('addClass', function() {
return function(text, opt) {
var i;
$.each(opt.scope.items,function(index,item) {
if (item.id === opt.item.id) {
i = index;
return false;
}
});
var elem = angular.element("select > option[value='" + i + "']");
var classTail = opt.className;
if (opt.eligible) {
elem.addClass('is-' + classTail);
elem.removeClass('not-' + classTail);
} else {
elem.addClass('not-' + classTail);
elem.removeClass('is-' + classTail);
}
return text;
}
})
app.controller('MainCtrl', function($scope) {
$scope.items = [
{ name: 'foo',id: 'x1',eligible: true},
{ name: 'bar',id: 'x2',eligible: false},
{ name: 'test',id: 'x3',eligible: true}
];
});
Here you can see it work.
The accepted answer did not work for me, so I found an alternative without a custom directive using track by :
<select ng-model="foo" ng-options="x.name for x in items track by x.eligible"></select>
Each option now gets the value x.eligible. In CSS you can style options with value = true (I think true has to be a string). CSS:
option[value="true"]{
color: red;
}
In case you not only want to show them in red color but prevent the user from selecting the options, you can use disable when:
<select
ng-model="Blah"
ng-options="person.Name disable when !person.Eligible for person in persons">
</select>
You can then use CSS to set the color of disabled options.
I can't write this as a comment, due to reputation, but I have updated the plunker for the accepted answer to work with Angular 1.4.8. Thanks to Ben Lesh for the original answer, it helped me a lot. The difference seems to be that newer Angular generates options like this:
<option class="is-eligible" label="foo" value="object:1">foo</option>
so the code
option = elem.find('option[value=' + index + ']');
wouldn't be able to find the option. My change parses ngOptions and determines what field of item was used for the label, and finds the option based on that instead of value. See:
http://plnkr.co/edit/MMZfuNZyouaNGulfJn41
I know I am a bit late to the party, but for people who want to solve this with pure CSS, without using a directive you can make a css class like this:
select.blueSelect option[value="false"]{
color:#01aac7;
}
This css rule says : Find all elements with value = false with tag name 'option' inside every 'select' that has a class "blueSelect" and make the text color #01aac7; (a shade of blue)
In your case your HTML will look like this:
<select class="form-control blueSelect" name="persons" id="persons1"
ng-options="person as person.name for person in $ctrl.persons track by person.Eligible"
ng-model="$ctrl.selectedPerson" required>
<option disabled selected value="">Default value</option>
</select>
The track by inside the ng-options is what will hold what to track the options by, or the "value" field of each option. Notice that depending on your project needs , you might have to do some tweaking to make this work as per your requirements.
But that's not going to work right when there's multiple options with the same value for the Eligible field. So to make this work, we create a compound expression to track by, that way we can have unique values to track by in each option. In this case we combine both fields Name and Eligible
So now our html will look like this
<select class="form-control blueSelect" name="persons" id="persons2"
ng-options="person as person.name for person in $ctrl.persons track by (person.name + person.Eligible)"
ng-model="$ctrl.selectedPerson" required>
<option disabled selected value="">Default value</option>
</select>
and our css :
select.blueSelect option[value*="False"]{
color:#01aac7;
}
Notice the * next to value, this is a regular expression which means to find the word "False" somewhere in the value field of the option element.
Quick Edit
You can also choose to disable the options with Eligible = False using the "disable when" in the ng-options expression , for example:
label disable when disable for value in array track by trackexpr
I'll leave how to use that in your case for you to find out ;-)
This works for simple css modifications, for more complex stuff you might need a directive or other methods. Tested in chrome.
I hope this helps someone out there. :-)
I've found another workaround that was easier than adding a directive or filter, which is to add a handler for the onfocus event that applies the style.
angular.element('select.styled').focus( function() {
angular.element(this).find('option').addClass('myStyle');
});

$_post in Kohana controller

i was wondering if i can get a variable with $_post, in a kohana controller if the controller doesn't 'control' a form.
So, if i insert in a view something like:
<form name="ordering" id="ordering" method="post" action="">
<input type="hidden" id="ordering" value="0">
<select id="ordering" name="ordering">
....
in the controller i put :
$ordering = $_POST['ordering'];
but gives me an error
or
if ($this->request->method == 'POST') {
$ordering = $_POST['ordering'];
}
but in this case it never gets there(at this bunch of code).
so my question is: how can i retrieve in a controller a $_post variable if the controller doesn't handle only a form? thank you!
Kohana 3.0 :
if ($_POST)
{
$ordering = arr::get($_POST, 'ordering');
...
Kohana 3.1 :
if ($ordering = $this->request->post('ordering')) // or just $this->request->post()
{
...
PHP will issue a notice if you attempt to access an undefined array element.
So if the "ordering" form was never submitted, attempting to access $_POST['ordering'] will result in
PHP Notice: Undefined index: ordering in ...
Kohana's Arr class provides a nice helper method to get around this.
If you call
$ordering = Arr::get($_POST, 'ordering', 0);
It will retrieve the ordering value from the post variable. If $_POST['ordering'] is not set, it will return the third parameter instead. You can then try if ($ordering) ...
This is useful for $_POST/$_GET arrays, or any function that accepts arrays – it allows you to concisely specify a fallback behavior rather than having to test with isset.
One of the advantages of Kohana is that the source code tends to be very clean and easy to understand (which is nice because documentation is sparse.) I'd suggest you take a check out the Kohana_Arr class and look at the methods available!
ID's are unique! Use class insted or different IDs.
Your form and the select both have got ordering, change one to something else, like:
<form name="ordering_form" id="ordering_form" method="post" action="">
<input type="hidden" id="ordering_input" value="0">
<select id="ordering" name="ordering">
...
</select>
</form>
and in your Kohana Controller:
if( isset( $_POST['ordering'] ) )
{
$ordering = $_POST['ordering'];
}
this should work, because i cant find any other error