I have a template who is iterating on a list of numbers and create a form. I don't want the changes made to the forms propagated to the underlying values, therefore, i am using a one way-binding.
Unfortunately, it doesnt't seems to work : JSBin
Thanks you a lot !
Your problem is that the Binding is setup at the "list" level, so the oneWay binding does not apply to specific items and their properties.
Instead of a oneWay binding, you can create a computed property which generates a new copy of your list.
Related
Let's say I have a SearchForm Component that has a Reset button, as well as a slot to include any desired SearchField Components. When I click SearchForm's Reset button, I'd like to call each SearchField's reset method, but I'm having a hard time understanding how to do this dynamically... I obviously don't want to add refs to each SearchField because these aren't static and can change when using the SearchForm in some other part of the application. Fiddle for example.
In Vue2, it seemed liked there was some sort of $children property, but that was taken out in Vue3. I was thinking I could potentially use querySelectorAll to access all "input" elements, but I didn't see how I could access the DOM element's component instance (similar to jQuery's $ selector). If I access the $slots.default() and loop over it, I get some weird object that isn't a component instance... or rather, it doesn't have the typical properties that the component instance has, and I have no clue how to access the actual instance from here.
It's also possible I'm not thinking in a Vue-centric way, as I'm new to the framework, so how can I solve this issue?
I've come up with this solution, but I don't like it, as it adds some minor coupling. Basically, I listen for when the field is created, check its parent, and if it's a form, I push it onto the array of children. Then when the parent's reset is called, it loops through its children. This is a fragile approach because it requires the direct parent to be the form... if the field was nested inside of another component, it won't be added to the form's fields. I'm also pretty sure this breaks the best practices of the framework. It's a shame there doesn't appear to be a way of accessing child instances (without being forced to use ref)... that seems like it'd be desired by a lot of devs.
I came up with yet another way, but once again, seems a little shady because I'm accessing the DOM element's private property __vueParentComponent. I like it better than the previous answer because it's not coupled, and I can use getElementsByTagName. Fiddle for reference. This is the relevant code that I added as a method in SearchForm:
getFields() {
const fields = this.$el.getElementsByTagName("input");
// getElementsByTagName returns an HTMLCollection, which doesn't have map,
// so let's use spread to make an array and use map
return [...fields].map((fieldEl) => {
return fieldEl.__vueParentComponent.proxy;
});
}
Last solution... this one seems to be more stable and the proper Vue way. You use provide/inject; the parent provides the value, and the child injects it, so it can use it. Vuetify does something similar, but they have their own register and unregister methods, which I've created in the Fiddle but as a rudimentary implementation. The only caveat being if you're using TypeScript, the inject won't work properly, and you'll have to use one of these solutions.
I have a situation in which I get data over a web socket, and performance is important. From the docs I understand that there are various ways of "pushing" the data I'm receiving to my Polymer elements, but I'm curious which one will be most efficient. So far I've created an element that can be included in a template, where the parent element will observe any changes in the data property and react accordingly. I've also been experimenting with using a Behavior to accomplish the same thing, though instead of needing to include a "data-element" in its template, it could just observe its own data property. I realize I could also use something like iron-signals to "push" the data via an event.
I'm not sure any of these methods are very efficient, since most of the time the changes to the "data" object will only apply to a small subset of all the observers. Another possible solution would be to "observe" a dynamic path, so like data.pathx instead of data.*, which would drastically reduce the number of times the observer callback gets fired, but I haven't come across anything that leads me to think that's possible, since each of my elements won't know if it should observe pathx or pathz until creation.
Like I said, performance is vital, and I feel there is way too much inefficiency if I have a small to medium sized dom-repeat of elements each observing a large data object of another element or individually holding a copy of that data on their own (like I assume a behavior would accomplish?).
I've looked at iron-meta, but I haven't been able to successfully data-bind to it, and from what I can tell from the docs, this data needs to be queried, whereas I need to be notified of changes.
Polymer doesn't really "observe" changes in elements. It just sets a setter for each property, and when it's called the UI is updated. So a dom-repeat template will not observe any change inside an object bound to it.
What could impact performance is unnecessary DOM manipulation, so if just a small subset of the data changes, re assigning all the array to the property is not ideal, and you should use notifyPath with just the sub property path and value that changed. Polymer will only update the DOM nodes affected.
If you have a way of knowing what sub properties changed in your data then you could obtain the object paths that have changed and call notifyPath for each of those and only a small number of DOM nodes will be changed.
Additional note:
If the number of elements in your array change, (added/removed) you should use the Polymer base array manipulation methods to update the property of your Polymer element, so it will change the DOM efficiently.
I have a big object lined in $rootScope (say > 100 objects and each having hierarchy of objects/array again), I want to $watch entire $rootScope with deepWatching(i.e. turning 3rd parameter of $watch to TRUE).
But the problem here is, $watch returns 2 objects (i.e. one Old RootScope and Modified RootScope). Then I have to do a process of checking what attribute of object changed in $rootScope and its hierarchy to PUSH it into stack.
Do we have an easy way out to get the exact attribute changed while watching a $scope?
$scope.$watch($rootScope, function(oldObj, newObj){
//all I want here is exactly what attribute changed, NOT entire objects!
}, true);
Alternatively, I could add watch on each attribute of the Object but it appears to be extremely expensive.
What is the best way to achieve undo/redo in angular js?
Note :-
angular-history doesnt suit my need because I want to watch all attributes of object, which may also contain other objects and array.
I'm certain watching entire $rootScope is not a good idea either, but I have aimed to build an UI which has several grids, drag n drop, might contain form, elements can be deleted. So I want to build an overall solution to stack the changes and undo it on CTRL + Z. Imagine replicating desktop version of Photoshop.
Undo/redo is based on the command pattern. And yes, there will be a lot of watches; such a rich functionality does not come cheap.
Just for the fun of it, here is a simple (but quite usable and extensible) implementation: http://jsfiddle.net/sYc4e/1/
A command is an interface for objects that know how to apply and rollback a change:
function XxxCommand() {
// implementation specific
}
Command.prototype.execute = function() {
// implementation specific
};
Command.prototype.rollback = function() {
// implementation specific
};
Usage: You decorate the <input>s with a directive:
<input name="name" undoable ng-model="data.name" />
And wrap them with an element (e.g. the <form>) with the undo-support directive:
<form undo-support>
The link function of undoable listens for a change in the <input> and registers a command with the undoableSupport. The controller of undoableSupport keeps track of the command list.
There's also an undo/redo library called Angular-Chronicle. For myself at least, it was a better option than angular-history.
The library angular-history provides undo/redo.
Currently not maintained. Most recent fork seems to be https://github.com/domoritz/angular-history.
instead of watching the whole $rootScope or for that matter any one object that contains a lot of items which in turn contain a lot of items requiring you to iterate through that nested array on every digest, I would use an array(using it as a queue) of changes that are applied to the original data model and a variable that points to a current location in that queue.
I would put that array and that variable in a service and then change that index whenever undo/redo happens. You can watch that variable from everywhere that you need to respond to these changes, like directives
I think the LazyJsonUndoRedo is what you're looking for.
https://github.com/azazdeaz/LazyJsonUndoRedo
From the readme:
A 'drop in' history handler with automatic undo/redo functionality for nested javascript objects, using ES6 Object.observe() or Polymer shim.
http://dailyjs.com/2014/07/18/lazy-json-undo/
I am having a form, which comprises of several textboxes and one button.
I am using the Kendo UI MVVM format. How shall I get the value of each textbox and store it in an object on click of the button?
Will I have to use normal jQuery in order to get the values or is there some other way of getting the values from each of them?
Thanks
Hardik
Please take a look at these documentation pages:
http://demos.kendoui.com/web/mvvm/index.html
http://docs.kendoui.com/getting-started/framework/mvvm/observableobject
http://docs.kendoui.com/tutorials/mvvm-in-kendo-ui
These pages contain answers to most of the questions you'll have concerning Kendo UI MVVM. It would be silly and presumptuous of me to think that I could explain it better than the qualified and hard working individuals at Telerik that have so painstakingly compiled these documentation pages.
The gist of it is that you need to create an instance of the kendo.data.ObservableObject that has properties for the values you are working with. This is your view-model. Then in your markup for your text boxes, include values for the data-bind attribute that reference the properties in your observable object. Create a function in your view-model to handle the button's click event. Put a data-bind attribute in your button that binds the click event to your function. Finally, call kendo.bind(<element>, <observable object>), and that will connect the wires from your markup to your view-model object.
In your click event-handler, you can take the values of the view-model, and insert them into the object you need. You should not need to use "normal jQuery" for anything besides referencing the element to call bind on.
Quickly you can retrieve the value this way using JQuery:
$('#yourTextBoxID').data('kendoMaskedTextBox').value();
you can use this code:
$('#yourTextBoxID').val();
I am attempting to create a reusable backbone view that represents a select element, and supports the following:
Setting a selected value from a model
Binding other select views to it, so that when its value changes, other select views update their collections
I've seen a few different resources on this, such as
http://blog.shinetech.com/2011/07/25/cascading-select-boxes-with-backbone-js/
http://railsindirection.blogspot.com/2011/08/backbonejs-and-dependent-selects.html
However neither of them seems to support a generalized object that fulfills both purposes - they seem to be hackish.
Does anyone have any advice on how to go about creating this? Or maybe a link to someone else's code that solves this problem elegantly?
Thanks
I would recommend you to implement event aggreator this way.
http://lostechies.com/derickbailey/category/backbone-eventbinder/
so you bind the change event on your select list inside the first view to a method that triggres the update in the other views.
Hope this helps