I'm at a loss for how to do something extremely simple: Get the current value of a AutoComplete YUI3 widget. I have the following markup:
<label for="targets">Target:</label>
<input id="targets" type="text"></input>
<label for="packets">Packet:</label>
<input id="packets"></input>
I have the following Javascript:
YUI().use("autocomplete", function(Y) {
Y.one('body').addClass('yui3-skin-sam');
var tgt = new Y.AutoComplete({
inputNode: '#targets',
source: '/telemetry/targets?target={query}',
render: true
})
var pkt = new Y.AutoComplete({
inputNode: '#packets',
source: '/telemetry/packets?target='+tgt.get('value')+',packet={query}',
render: true
})
});
tgt.get('value') always returns an empty string no matter what I have typed into the #targets input. What am I doing wrong?
tgt.get('value') is the right way to get the current value of the inputNode, but in this case it's being called immediately when the value of the source attribute is set at instantiation, not when the request is made later. Since no text has been entered at this point, the value is empty.
If you want the "target" parameter of the second AutoComplete instance to be set to the current value of the first AutoComplete instance's inputNode, the best thing to do would be to set a custom requestTemplate for the pkt instance:
var pkt = new Y.AutoComplete({
inputNode: '#packets',
source: '/telemetry/packets',
requestTemplate: function () {
return '?query=' + encodeURIComponent(pkt.get('query')) +
'&target=' + encodeURIComponent(tgt.get('value'));
},
render: true
});
This will ensure that the query string of each request is generated at request time rather than at instantiation time.
Related
I have tried multiple options that I have found on SO and elsewhere for clearing form inputs, all listed below in the code, but nothing seems to work. Is there anything specific about this form that would determine which one I should use?
<template name="CompanyAdd">
<div>
<form class="form-inline">
<div class="form-group">
{{> inputAutocomplete settings=companySettings id="companyAdd" name="companyAdd" class="input-xlarge" autocomplete="off" placeholder="Add Company"}}
</div>
<button type="submit" class="btn btn-default company-add">Add</button>
</form>
</div>
</template
Template.CompanyAdd.events({
'submit form': function(e) {
e.preventDefault();
var selection = $(e.target).find('[id=companyAdd]').val();
var company = {
ticker: selection
};
if(Companies.findOne({ticker:selection})) {
console.log("Do nothing");
} else {
Meteor.call('companyAdd', company, function(error, result) {
});
}
//event.target.reset();
//e.target.reset();
//target.text.value = '';
//template.find("form").reset();
//document.getElementById("companyAdd").reset();
}
});
Given that you have
var selection = $(e.target).find('[id=companyAdd]').val();
That is the input you want to clear and that - I assume - works, I would do:
var field = $(e.target).find('[id=companyAdd]');
var selection = field.val();
...
field.val('')
Otherwise if you wish to reset all form, go for #JeremyK`s #reset.
Your second attempt:
e.target.reset();
should work fine. If it is not working, check if there are any errors in the console and report back here.
The handler function receives two arguments: event, an object with
information about the event, and template, a template instance for the
template where the handler is defined.
In your code above you define your handler like this:
'submit form': function(e) {
You have named the event argument e, and discarded the template argument.
e is has information about the event
e.target is the form element (The event was defined on 'submit form')
e.target.reset succeeds because reset is a valid function to call on a form.
Briefly, your other attempts failed because:
event.target.reset(); event is not defined or passed in, at least not with the name event (you used e)
target.text.value = ''; target is an undefined variable
template.find("form").reset(); this fails because template is undefined. If you change your handler definition to receive the template variable, this will work (change 'submit form': function(e) to 'submit form': function(e, template)
document.getElementById("companyAdd").reset(); This fails because the element with the id companyAdd is the input element, not the form, so .reset() is undefined. You could change this to document.getElementById("companyAdd").text.value = ''
I've been on this one for days, and all my reading hasn't helped me find a clean solution for this particular case.
Issue
I can send a parent state value and callback down to a nested component, but once the callback is triggered in the child I don't know how I can send the updated value back to the parent so it can update the correct value.
For instance
Parent Component (Has values and the callback)
Child Component (Values and callback is passed here)
Grand Child Component (Values Updated here and callback triggered)
What is SEEMS to cause the Issue
It seems the issue is I need the original key name in order for "setState" to update the correct value in the parent component(or at least it seems that way), but the child component only has original value and new updated value and has no access to the key associated with original value in the parent component.
Important Notes on Best Practice Surrounding this question
-From what I understand it is bad practice to use refs to handle nested situations like this.
-It seems like there is a cleaner solution than sending a prop for the key and another for the value.
-I'm assuming also that flux might provide a solution to this issue but I feel that there is a basic component to component communication technique or principle that I'm missing here.
Here is a bare bones example of what I'm dealing with.
/*All the values need to be updated here so that the inputs can used for calculation and then sent to a component that displays the output*/
var Calculator =
React.createClass({
getInitialState:function(){
return {
value1: "Enter value 1", /*These values are passed to a nested child component, can't figure how to update the right one*/
value2: "Enter value 2",
}
},
update: function(update){
this.setState(
update
);
},
render: function () {
return (
<div>
<h2>Input</h2>
<Input onClick={this.handleClick} update={this.update} value1={this.state.value1} value2={this.state.value2} /> //pass the values here
<h2>Output</h2>
<Output />
</div>
);
},
handleClick: function () {
//want to update the state for the correct value here
}
});
/* A compenent that is a middle layer between the parent and nested child component I'm working with*/
var Input =
React.createClass({
update: function(){
this.props.update();
},
render:function(){
return (
<div>
<p><InputComponent update={this.update} value={this.props.value1} /> / <InputComponent value={this.props.value2}/></p>//passing down values again
<p><ButtonComponent onClick={this.props.onClick} /></p>
</div>
)
}
});
/*This is the child component that gets the value and call back from the top level component. It will get updates to the values and send them back to change state of the parent component.*/
var InputComponent =
React.createClass({
handleChange: function(event) {
this.props.update();
},
render: function() {
return <input type="text" value={this.props.value} onChange={this.handleChange} />; //this props value has no key associated with it. Cant't make update object ie {originalkey:newValue}
}
});
/* This component is triggered to carry out calculations in the parent class.*/
var ButtonComponent =
React.createClass({
render:function(){
return <button onClick={this.handleClick}> {this.props.txt} </button>
},
handleClick: function(){
this.props.onClick();
}
});
/*The inputs will be calculated and turned to outputs that will displayed here.This component doesn't matter for the question so I left it empty*/
var Output =
React.createClass({
});
Here's an example I just put together on jsfiddle.
Instead of putting update in setState, we pass a value to update from the child component and let the parent set its state.
In the parent, we have:
_update: function(val){
this.setState({
msg: val
});
},
render: function() {
return (
<div>
<p>Message: {this.state.msg}</p>
<Child _update={this._update} />
</div>
);
}
And in the child, we have a _handleClick function that calls the parent _update function with values:
_handleClick: function(){
this.props._update(React.findDOMNode(this.refs.text).value);
},
render: function(){
return (
<div>
<input type="text" ref="text" />
<button onClick={this._handleClick}>Update</button>
</div>
);
}
How do I go about locating & getting a value for an element like the following?
<input type="hidden" title="username" value="joe.doe">
Any suggestions much appreciated.
var userNameElm = $('input[title=username]');
it('is present but invisible', function() {
expect(userNameElm.isPresent()).toBeTruthy();
expect(userNameElm.isDisplayed()).toBeFalsy();
});
it('should have proper value attribute', function() {
expect(userNameElm.getAttribute('value')).toEqual('joe.doe');
});
If you are trying to access an element with data-* attributes as we would do in Bootstrap, we can select such elements as follows:-
var loginBtn = $('a[data-target="#login-modal"]');
This is same as the accepted answer except that it has "" around #login-modal. Without the "", it doesn't work.
Good Luck.
I'm doing something wrong. I'm attempting to get the stored value I have in goinstant. I have a person room with a userName. The value the alert function displays is "[object Object]". Here is my code: (I left out the scripts intentionally). I provided a quick screen shot of my person data on goInstant for reference http://screencast.com/t/BtLqfrorg
<h2>Angular JS Test</h2>
<div ng-app="testapp" data-ng-controller="personCtrl">
<input type="text" ng-model="userName" />{{ userName }}
<button type="submit" id="save" name="save" >Save</button>
<script>
var testApp = angular.module('testapp', ['goangular']);
testApp.config(function($goConnectionProvider) {
$goConnectionProvider.$set('https://goinstant.net/<mykey>/test');
});
testApp.controller('personCtrl', function($scope, $goKey) {
// $goKey is available
$scope.userName = $goKey('/person/userName').$sync();
alert($scope.userName);
});
</script>
</div>
Your example would indicate that you expect $scope.userName to be a primitive value (a string). It is in fact, a model. Models provide a simple interface for updating the state of your application, and in GoAngular, that state is persisted to your GoInstant App auto-magically.
You can find more documentation on the GoAngular Model here. I thought a working example might help, so I've created a Plunker. Let's work through the script.js:
angular
.module('TestThings', ['goangular'])
.config(function($goConnectionProvider) {
$goConnectionProvider.$set('https://goinstant.net/mattcreager/DingDong');
})
.controller('TestCtrl', function($scope, $goKey) {
// Create a person model
$scope.person = $goKey('person').$sync();
// Observe the model for changes
$scope.$watchCollection('person', function(a, b) {
console.log('model is', a.$omit()); // Log current state of person
console.log('model was', b.$omit()); // Log the previous state of person
});
// After 2000 ms set the userName property of the person model
setTimeout(function() {
$scope.person.$key('userName').$set('Luke Skywalker');
}, 2000);
// Set the userName property of the person model
$scope.person.$key('userName').$set('Darth Vader');
});
Not sure if this is possible but I'm trying, and keep coming up short.
http://plnkr.co/edit/Gcvm0X?p=info
I want a 'E' (element) directive that is replaced with a more complex nested HTML node using the 'templateUrl' feature of directives.
HTML defining the directive (form tag included for complete mental image):
<form id="frm" name="frm">
<ds-frm-input-container
class="col-md-1"
frm-Name="frm"
frm-obj="frm"
input-name="txtFName"
ds-model="user.firstName"></ds-frm-input-container>
</form>
TemplateUrl contents which 'replaces' the above directive 'ds-frm-input-container' HTML element:
<div>
<input
required
ng-minlength=0
ng-maxlength=50
class="form-control"
ng-model="dsModel"
placeholder="{{dsPlaceHolder}}" />
<span ng-if="showErrs" class="label label-danger">FFFFF: {{dsModel}}</span>
</div>
Controller and Directive:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = "Nacho";
$scope.user = {};
$scope.user.firstName = "";
})
.directive('dsFrmInputContainer', function(){
var ddo = {
priority: 0,
restrict: 'AE',
scope:
{
frmName: '#',
inputName: '#',
dsPlaceHolder: '#',
dsModel: '=',
frmObj: '='
},
templateUrl: 'template1.html',
replace: true,
controller: function($scope)
{
$scope.showErrs = true;
},
compile: function compile(ele, attr) {
return {
pre: function preLink(scope, ele, attr, controller)
{
},
post: function postLink(scope, ele, attr, controller)
{
var txt = ele.find('input');
txt.attr('id', scope.inputName);
txt.attr('name', scope.inputName);
//BLUR
txt.bind('blur', function () {
console.log("BLUR BLUR BLUR");
angular.forEach(scope.frmObj.$error, function(value, key){
var type = scope.frmObj.$error[key];
for(var x=0; x < type.length; x++){
console.log(type[x]);
}
});
event.stopPropagation();
event.preventDefault();
});
}
};
},
};
return ddo;
});
The directive replaces just fine and the input element is named just fine. The form object however doesn't include the input element name in the error information. This makes it impossible for me to single out the input element during a 'blur' event that is setup in the directive.
I am doing this trying to reduce the show/hide logic 'noise' in the html for error messages (spans) and it should be reusable.
UPDATE (2014.01.28):
2014.01.28:
Added promises. There is a service that allows validation on button clicks. NOT USING built in angular validation anymore found some compatibility issues with another library (or viceversa).
ORIGINAL:
Here is my form validation directive vision completed (plnkr link below). Completed in concert with the help of the stack overflow community. It may not be perfect but neither are butterfingers but they taste good.
http://plnkr.co/edit/bek8WR?p=info
So here is a link that has the name variables set as expected on the given input form error object. http://plnkr.co/edit/MruulPncY8Nja1BUfohp?p=preview
The only difference is that the inputName is read from the attrs object and is not part of the scope. This is then read before the link function is returned, in the compile phase, to set the template DOM correctly.
I have just spent quite a while trying to sort this problem out, and while this is not exactly what you were looking for, his is my attempt. It uses bootstrap for all the styling, and allows for required and blur validation, but its definitely not finished yet. Any thoughts or advice much appreciated.
https://github.com/mylescc/angular-super-input