Vue calling method in children in v-for - methods

I have a component in a v-for
<div
v-for="(plan, index) in plans"
:key="index"
>
<plan
:name="plan.name"
:cost="plan.cost"
:index="index"
ref="myPlan"
/>
</div>
Within that component I have a method which clears all the data.
clear() {
this.cost = '';
// some more clearing code
},
I am trying to clear the plan by calling this method.
this.$refs.myPlan.clear();
This does not work because the ref is an array, but this does clear the first plans
this.$refs.myPlan[0].clear();
How can I call the clear method on all of the plans?

Related

Livewire - updated hook without render of complex data

I'm using Livewire for data table with a complex database query with pagination. In table are also checkboxes and after check/uncheck is quite annoying to wait for render method with fetching all necessary data witch are required only for first component load.
I know I can use defer flag for checkboxes but I need also do some action when is any checkbox checked/unchecked so I cannot use that flag. So my question is if I can use updated hook method for checkbox without loading data in render.
Here is my example code:
class LivewireComponent extends Component
{
public $arrayOfCheckboxes = [];
public function render(SomeService $service)
{
$data = $service->fetchComplexData->paginate();
return view('livewire.some-component', ['data' => $data]);
}
public function updatedArrayOfCheckboxes($value)
{
// if value is true/false then do some action
// do I really need to call render and fetch complex data again?
}
}
// livewire.some-component.blade.php
<div>
<table>
#foreach($data as $row)
<input type="checkbox" wire:model="arrayOfCheckboxes" value="{{ $row->someValue }}">
#endforeach
</table>
</div>

Grails: how to pass a array (and not a string!) using remoteFunction (ajax) from controller to view?

I need to load different data in a div when I change a Select option, not only a simple string but I list/array/map of strings. My code:
View:
<div id="contextMenu">
<div id="testeDiv">${result}</div>
<form class="selecionarConta" name="formulario">
<g:select id="selecionaConta"
name="selecionarConta"
class="selectConta"
from="${menuDropDown}"
optionValue="string"
optionKey="value"
onchange="${remoteFunction(controller:'dashboard',action:'teste', update:'testeDiv', params:'\'varteste=\'+this.value')}"/>
</form>
</div>
Controller:
def teste() {
def result = [["Lemon":"${params.varteste}"],["Orange":"5"],["Grapefruit":"10"]]
[result:result]
}
Let's suppose I want to load an array or even an object in this div "testeDiv" and then any content I want, e.g. a list, or even a single element from this list e.g. <div id=testeDiv>${result[1]}</div>

Can one avoid multiple DOM elements with same id, when using Backbone/Marionette view instances?

When I create multiple view instances of the Marionette view which is linked with a template html with ids, these would get duplicated for multiple instances of these views.
While it works correctly, I feel that there ought to be more architecturally correct way of doing this.
The example code is like below.
Template:
<script id="myTemplate" type="text/template">
<div id="myDiv">
<input type="text" id="myText"/>
<input type="button" id="myBtn" value="Click me!"/>
</div>
</script>
View:
MyView = Backbone.Marionette.ItemView.extend({
template: '#myTemplate',
events: {
'click #myBtn' : 'myFunc' //Correctly identifies its own 'myBtn'
},
myFunc : function() {
alert($('myText').val()); //Again, picks own 'myText'
}
});
var v1= new MyView();
v1.render();
var v2= new MyView();
v2.render(); //Duplicate IDs now present in DOM
I need some unique identification of these DOM elements and hence the ids.
Even when tying the model to this view, we need some way to identify these DOM elements.
What is the correct way of doing this without duplicating the ids.
Just pass the id to the view when you create it:
Template:
<script id="myTemplate" type="text/template">
<input type="text" class="js-myText"/>
<input type="button" class="js-myBtn" value="Click me!"/>
</script>
View def:
MyView = Backbone.Marionette.ItemView.extend({
template: '#myTemplate',
events: {
'click #myBtn' : 'myFunc' //Correctly identifies its own 'myBtn'
},
myFunc : function() {
alert($('myText').val()); //Again, picks own 'myText'
}
});
Instanciation:
var v1= new MyView({ id: "view" + number});
v1.render();
Then you can provide dynamic id values for your views (e.g. by using a model id).
That said, when using Marionette you shouldn't need to call render: you should instead show a view within a region. Take a look at the free sample to my Marionette book to get you up to speed.
If you must go for unique IDs to make sure no one accidentally duplicates a class name inside a view, you can use:
Underscore's uniqueId method to generate a unique ID for each DOM element inside the view, like: <input type="text" id= <%= _.uniqueId("myText_") %> /> This will just make sure that IDs are not duplicated. But they're not very helpful if you need to identify the elements by these IDs.
Marionette's TemplateHelpers which allow you to use helper functions from inside the templates:
//Define this inside your view:
templateHelpers: function() {
var that = this;
return {
getIdSuffix : function() { return that.idSuffix; }
/*Where idSuffix is passed to the view during instantiation
and assigned to this.idSuffix */
};
}
//In the template:
<input type="text" id= <%= "myText_" + getIdSuffix() %> />
You now know before runtime what DOM IDs you will have, provided care is taken not to give the same idSuffix to more than one view instance.
Simply put, don't use an id if it's not unique. Use a class or some other way of identifying the element.
You can use any jQuery selector to locate the element you want, ranging from the insane and brittle:
this.$('div > input:first'); // don't actually do this!
to the slower but semantically better:
this.$('[data-element-type="some-text-box-descriptive-name"]');
Although in reality, using a class is best, because that's what a class is for - for identifying a type of element. I can see that a maintainer might not know not to change your class in the template, so a data-attribute might be acceptable, or maybe even (in this case):
this.$('input[type=text]');

Multiple views for one model in AngularJS

I'm learning AngularJS framework and my background is BackboneJS and it seems I can not figure
out conventional way to do next thing:
I have a readonly list of elements each of which has 'edit' button that switches this
particular element to an edit mode. In edit mode I need to render input elements instead
of spans, p's etc.
The way to do this in Backbone.js is simply create EditView and pass model to it, but I don't have any idea how this works in Angular.
I pass data to the scope and render the readonly list and when user clicks on 'edit' button
in the element how should I change view for the element?
Thanks!
Angular makes this task simpler than Backbone by using a model for editing, then you update the original list and clear the edit model.
The view:
<div ng-app='App'>
<div ng-controller='mainCtrl'>
<div ng-controller='childCtrl'>
<strong>Controller</strong>
<ul>
<li ng-repeat='item in list'>{{item.name}} <button ng-click='edit($index)'>+</button></li>
</ul>
<div ng-show='editModel.name'>
Name: <input type="text" ng-model='editModel.name'/> <button ng-click='save()'>Save</button><button ng-click='cancelEdit()'>Cancel</button>
</div>
</div>
</div>
The angular app:
angular.module('App', [])
.controller('mainCtrl', ['$scope', function($scope){
$scope.list = [ {name:'item 1'}, {name:'item 2'}, {name:'item 3'} ];
}])
.controller('childCtrl', ['$scope', function($scope){
$scope.editModel = {};
$scope.edit = function(index){
$scope.editModel.index = index;
$scope.editModel.name = $scope.list[index].name;
};
$scope.cancelEdit = function(){
$scope.editModel = {};
};
$scope.save = function(){
if($scope.editModel.hasOwnProperty('index')){
$scope.list[$scope.editModel.index] = $scope.editModel;
}
else if($scope.editModel.name && $scope.editModel.name.length){
$scope.list.push($scope.editModel);
}
$scope.cancelEdit();
};
}]);
JsFiddle: http://jsfiddle.net/guilhermenagatomo/Bp6bY/
I'm using the controller nesting so the list can be used by other controllers you have in the app, or maybe you can create a controller just to take care of the editing.

Validation of dynamic created form (AngularJS)

I try to made nested form with validation. All works fine, but when I remove one of nested form, validation continue to use removed form. I made jsfiddle example http://jsfiddle.net/sokolov_stas/VAyXu/
When example runs, form are valid. If click "+" button, nested form will be added and valid will be false. Then click "-" button, and valid will be false all the same.
The question is: How to remove dynamic created form from validation processing.
Well, for one thing, a <form> inside of a <form> is not valid HTML.
Second, you're not supposed to be doing DOM manipulation from inside the controller. The controller is for "business" logic. See the section on controllers here
For what you're doing, you'd probably be better off using one form, with an ng-repeat inside of it, and adding additional elements to an array:
<form name="myForm" ng-controller="FormCtrl" ng-submit="doSomething()">
<div ng-repeat="item in items">
<input ng-model="item" type="text" required/>
</div>
<a ng-click="addItem()">+</a>
<a ng-click="removeItem()">-</a>
<button type="submit">Submit</button>
<div>Form valid: {{myForm.$valid}}</div>
</form>
and the controller:
function FormCtrl($scope) {
$scope.items = [];
$scope.addItem = function() {
$scope.items.push(null);
};
$scope.removeItem = function() {
$scope.items.pop();
};
$scope.doSomething = function () {
//your submission stuff goes here.
};
}

Resources