How can I binding a event with Angular 2 - javascript

This is a input label,
<input type="text" (blur) = "obj.action"/>
the obj is a object from corresponding component, obj.action = preCheck($event), preCheck(input: any) { code ....} is a function in the same component, could it works if i code like this?
My purpose is to distinguish which input need this event, because there are few input use the same template, i want to use attr action to ensure which one need this event.

There is just one small mistake in this code, you didn't add the parentheses "()" when adding "obj.action" as the blur event handler. So the corrected code is :-
<input type="text" (blur) = "obj.action()"/>

Related

geocomplete with Vue js -- location being erased

I'm trying to use jQuery geocomplete along with Vue.js to populate a form with geo data.
My code contains this form:
<form>
<label for="get-offer-location">location: </label><input id="get-offer-location" v-model="newoffer.location" type="text"/>
<div style="visibility:hidden">
<input name="lat" type="text" value=""/>
<input name="lng" type="text" value=""/>
</div>
</form>
After I click on a suggested location from the get-offer-location input, it looks like the field is filled out -- but then when I start typing in another field, the location input field reverts to just the letters I typed in for the location search. Try it out here by clicking "post", then "news" or "offers":
https://jsfiddle.net/dvdgdnjsph/157w6tk8/
Can anyone tell me what's wrong?
The problem you are having is that v-model binds on input, since the geolocation dropdown is a plugin that changes the value programatically the input event is not fired, so v-model is not updated. As a case, try typing a space after selecting a location, you will see that it sticks.
Fortunately, v-model is nothing more than syntactic sugar for v-on:input, so you can use v-on to fire your event instead. Considering that you are going to need to unfocus to get out of the box, the blur event is likely to be your best option, so you can simply do:
v-on:blur="newarticle.location = $event.target.value"
Unfortunately, JSFiddle won't let me save or update your Fiddle, but I did get it working with the code above.
For completeness, in case you want to use this behavior extensively, and because the Vue docs are fairly limited in this regard, you may write a custom directive to encapsulate the code:
Vue.directive('model-blur', {
bind: function(el, binding, vnode) {
el.addEventListener('blur', function() {
vnode.context[binding.expression] = el.value;
});
}
});
Then you can use like so:
<input v-model-blur="myVar" />
Here's the JSFiddle: https://jsfiddle.net/4vp6Lvmc/
Can't tell for sure. But it looks like jQuery plugin just changes input#get-article-location value, but not the Vue model. So when you trigger model update (e.g. editing headline) it overwrites complete location with whatever you typed in.
I have something like this for catch the geocomplete event and try to set the vueJS value :
$("#get-article-location")
.geocomplete({details: ".details"})
.bind("geocode:result", function (event, result) {
vm.newoffer.location = result.formatted_address;
console.log('done');
});
But something still appears wrong, I think you should really change the name of your vueJS instance (var vm) it may be use by another script and make troubles.
This is because v-model, as two-way binding, on the receiving-user-input way, listens to the input event on the input element, while js plugins (like jquery-geocomplete) obviously set input values via js, which leads to the view model's data not changing as we discussed in other answers.
To fix this, just listen to the geocode:result event of the plugin and manually change the data with code (there seems to be something wrong with jsfiddle so I'm posting it here):
var vueVM = this;
$("#get-offer-location").geocomplete({ details: ".details" });
$("#get-article-location")
.geocomplete({ details: ".details" })
/***** highlight start *****/
.bind("geocode:result", function(event, result){
console.log(result);
//tried result.something but couldn't find the the same thing as `this.value`
vueVM.newarticle.location = this.value;
});
/***** highlight end *****/
extra knowledge: the mechanism of v-model stated above is usually used in making reusable components, by receiving a value prop from the parent, and emitting an input event with the user-input value when detecting change on the input element in the component. And then we can use <my-component v-model='parentData'></my-component> as the child behaves exactly like a simple input element from the parent's perspective. example

jQuery click event does not update ':last' when i add a new element that should become the new ":last"

So i am having a small issue,
I am working on a small effect on jquery that works this way.
The user is provided with one input button.
as soon as he types something into the input field, a new input is added below it.
Here is the HTML
<div class="container">
<div class="row">
<div class="col-md-4 data">
<input type="text" class="form-control" placehoder="some text"/>
</div>
</div>
<span><i class="fa fa-plus"></i></span>
</div>
Here is the jquery code
$(document).ready(function()
{
var input_button = '<div class="col-md-4 data"><input type="text" class="form-control" placeholder="some text"/></div>';
var last = 'div.data input[type="text"]';
$('div.data input[type="text"]:last').on("keyup",function(e)
{
value = $(this).val().trim();
if(value.length != 0)
{
$('.row').append(input_button);
}
});
});
Therefore, i use the $(div.data input[type="text"]:last) selector and the keyup event.
However, in my own thinking, when i Add a new input button, it should automatically become the ":last" input field. right?
But this is not the case. The last input field is, according to how the code is working, the first input field that originally existed?
Basically the first original input button is considered the "last" button even when more are added by the keyup event.
So my question is, how do i make the newly added input field (added using jquery) the last input field on the next keyup event?
The problem is that you bind to elements that are searched only once, not to a dynamic selector.
You should use
$('div.data').on("keyup", 'input[type="text"]:last', function(e)
so that the 'input[type="text"]:last' selector is checked each time there's a keyup event in a descendant of an element of $('div.data').
As your question isn't clear, in case you also dynamically add the div.data element, then you should do
$('.container').on("keyup", 'div.data input[type="text"]:last', function(e)
To read more about event delegation in jQuery, you can check this page.
When you dynamically create an element you have to select a parent element that is not being dynamically created then use the on function to trigger a function on an event.
So in your case you have to select a parent that is not being dynamically created which is .row and use the on function as follows:
$('.row').on("keyup", 'input[type="text"]:last', function (e)
http://jsfiddle.net/55SNt/
As the content are dynamically added on the fly , the event handler defined in your question points to the static field generated on page load. Instead you should do :
$(document).on("keyup", 'div.data input[type="text"]:last', function(e)
{
value = $(this).val().trim();
if(value.length != 0)
{
$('.row').append(input_button);
}
});
here is the example.
See More about Event Delegation.
To understand what's going on, you have to consider what jQuery is doing:
//Your code:
$('div.data input[type="text"]:last').on("keyup", function(e) {
//...
});
It looks like one thing is happening there, but there are actually two:
First you wrap the last element that matches div.data input[type="text"] in a jQuery object,
Then you add a handler to it.
Once $('div.data input[type="text"]:last') runs, the element it contains isn't going to change. It's already been found. The event handler is operating on that specific element, not the position it occupies.
To fix this, you have to tell jQuery to bind the handler dynamically every time the event fires. Fortunately, the on method is clever about that, and gives you the option to do it differently:
$(document).on("keyup", 'div.data input[type="text"]:last', function(e) {
//...
});
This will search the entire document for 'div.data input[type="text"]:last' before firing the event handler.

Fire change event which was added using addEventListener

I have a page with the following markup:
<input type="checkbox" onclick="this.form.hiddenField.value=(this.checked?'Y':'N');">
<input type="hidden" name="hiddenField" value="N">
Pretty straight forward. A checkbox places 'Y' or 'N' in a hidden input when it's clicked.
In a js script I'm adding a "change" event listener like so (I left out some x-browser stuff):
myHiddenElement.addEventListener("change", function(e){
//do something
};
Since the hidden element is being changed programmatically, its onchange event does not fire. I thought adding this.form.hiddenField.onchange(); to the onclick of the checkbox would do the trick, but it does not.
Since I'm using element.addEventListener, the element.onchange is undefined.
How can I fire the change event for events added using addEventListener?
In modern browsers you could do:
input.dispatchEvent( new CustomEvent( "change" ) );
More simple way would be this:
function changeHandler(){
// whatever
}
input.addEventListener( "change", changeHandler, false );
...
changeHandler.call( input );
This is assuming that you don't need the event object in the handler, and typically for onchange you don't.
Another alternative is, of course to use something like jQ... (well, you know that word :) )
Yet another solution is to give a name and value to the checkbox itself and get rid of the hidden input. Checkboxes have been handled without any Javascript for years.
I think relying on the onchange of the hidden field is the less reliable option. The onchange event of hidden and text inputs is not as straightforward as you would think. (For instance, the onchange of a text field fires after the text field loses focus, not while you are typing Fiddle) It would be better to rely on the onclick or onchange of the checkbox.
JS
function checkChange(cb) {
if (cb.checked) {
cb.form.hiddenField.value = "Y";
//do checked stuff
} else {
cb.form.hiddenField.value = "N";
//do unchecked stuff
}
}
HTML
<input type="checkbox" onclick="checkChange(this)" />
<input type="hidden" name="hiddenField" value="N" />

How to detect changes besides the change event in knockout.js

I am using knockout.js. I created a view model say testViewModel with only 1 observable property testProperty.
function testViewModel()
{
var self = this;
self.testProperty = ko.observable("Initial");
}
than i created a span in which the changed value of testProperty is reflected and a input text field by which we can change the testProperty value.
<span data-bind="text: testProperty"></span><br />
<input type="text" data-bind="value: testProperty" />
I created an Example Fiddle.It seems that the observable property value is updated when the focusout event is executed on the input text field.
Now my question is that can we change the observable property value update event from focusout to something else. I created a save button also. Is there any way to update the observable property value only on save button press.
I am trying to create an application in which a user can create and save its profile and can edit the saved profile.I am using the same observable properties in create and edit form and these properties are observable. So when user edit its profile the ui should not
be updated until user press the save button. This is my goal. Please help me to solve this issue ?
I would suggest have testProperty and testProperty_temp. Bind the input to temp and when the button is clicked, set testProperty to the testProperty_temp
function testViewModel()
{
var self = this;
self.testProperty = ko.observable("Initial");
self.testProperty_temp = ko.obserable("");
self.save = function() { self.testProperty(self.testProperty_temp()); }
}
Hope this helps
Another means, along the same lines of what Matt Burland suggested:
http://jsfiddle.net/mori57/PQxJC/
Basically, wrap your input and button in a form, and bind the form to submit: which is handled by a method on your ViewModel. See the comments I've made inline, but here it is for people who don't want to go out to jsFiddle:
<span data-bind="text: testProperty"></span><br />
<!-- wrap the input and button in a form and
data-bind to submit, with a reference
to a handler on your viewmodel -->
<form data-bind="submit: updateProfile">
<!-- this must be bound to your shadow value -->
<input type="text" data-bind="value: _tmpTestProperty" />
<button type="submit">save</button>
</form>​
and in your javascript
function testViewModel()
{
var self = this;
self.testProperty = ko.observable("Initial");
// Create the "shadow" property
// and prepopulate it with testProperty's value
self._tmpTestProperty = ko.observable(self.testProperty());
// Create our form handler
self.updateProfile = function(val){
// set the testProperty value to the
// value of the shadow property
self.testProperty(self._tmpTestProperty());
};
}
ko.applyBindings(new testViewModel());​
In this way, your value doesn't change when you lose focus on the text input box, but is only updated when you submit the form.
Your simplest approach would be to have a shadow property for each of your properties. So you bind one to your text boxes and only copy the value to the other property, the one bound to the other UI elements, when save is clicked.
See here: http://jsbin.com/aguyud/5/edit
An easier way using two models and $.extend to copy from one to the other:
http://jsbin.com/aguyud/7/edit
Update, actually scratch that, that doesn't seem to work. I tried this instead:
http://jsbin.com/aguyud/22/edit
which works the first time, but after copying the model with $.extend it seem it's copied all the bindings too, so it only works once!

html text input onchange event

is there a way to implement a text change event to detect text change on an HTML input text field? It's possible to simulate these using key events (key press etc), however, it's really not performant and difficult, is there a better way?
onChange doesn't fire until you lose focus later. If you want to be really strict with instantaneous changes of all sorts, use:
<input
type = "text"
onchange = "myHandler();"
onkeypress = "this.onchange();"
onpaste = "this.onchange();"
oninput = "this.onchange();"
/>
When I'm doing something like this I use the onKeyUp event.
<script type="text/javascript">
function bar() {
//do stuff
}
<input type="text" name="foo" onKeyUp="return bar()" />
but if you don't want to use an HTML event you could try to use jQuerys .change() method
$('.target').change(function() {
//do stuff
});
in this example, the input would have to have a class "target"
if you're going to have multiple text boxes that you want to have done the same thing when their text is changed and you need their data then you could do this:
$('.target').change(function(event) {
//do stuff with the "event" object as the object that called the method
)};
that way you can use the same code, for multiple text boxes using the same class without having to rewrite any code.
Well unless I misunderstand you can just use the onChange attribute:
<input type="text" onChange="return bar()">
Note: in FF 3 (at least) this is not called until some the user has confirmed they are changed either by clicking away from the element, clicking enter, or other.
I used this line to listen for input events from javascript.
It is useful because it listens for text change and text pasted events.
myElement.addEventListener('input', e => { myEvent() });
Use the oninput event
<input type="text" oninput="myFunction();" />

Categories

Resources