I am having trouble actioning a callback function in one of my React classes. Basically I call checkSource on click and then if it meets a specific requirement I want to call handleSubmitClick. I have a feeling this has to do with me calling this.handleSubmitClick, but I don't understand. My understanding is that the this is referring to the component object that I created. If this is the case, shouldn't it just call that function and execute?
The full component is here:
var React = require('react');
module.exports = React.createClass({
getInitialState: function() {
return {
text: ''
}
},
handleTextInput: function(event){
this.setState({text: event.target.value})
},
checkSource: function(){
var clientId = 'xxxx';
var resolve = 'http://api.soundcloud.com/resolve?url=';
$.get(resolve + this.state.text + '&client_id=' + clientId, function(data) {
$.get('http://api.soundcloud.com/users/' + data.user.id + '/?client_id=' + clientId, function(data) {
if(data.followers_count < 3000) {
console.log("handleSubmitClick now");
this.handleSubmitClick();
} else {
return false;
}
});
});
},
handleSubmitClick: function() {
console.log('handleSubmitClick going')
console.log(this.state.text)
var linkStore = this.props.linkStore
linkStore.push(this.state.text)
this.setState({text: ''})
this.props.handleListSubmitClick(linkStore)
console.log(this.props.linkStore)
},
render: function() {
return <div className="row">
<div className="col-md-8 col-md-offset-2">
<div className="text-center">
<h1>Soundcloud3k</h1>
</div>
<div className="input-group">
<input
onChange = {this.handleTextInput}
type="text"
className="form-control"
placeholder="Search fr..."
value={this.state.text} />
<span className="input-group-btn">
<button
onClick={this.checkSource}
className="btn btn-default"
type="button">Submit!</button>
</span>
</div>
</div>
</div>
}
});
This is the render function with the checkSource call
The console logs for the checkSource function works as intended, but I can't get the handleSubmitClick to do anything. I don't get an error or anything in the console. Any ideas?
In $.get callback this does not refer to your component, you should set this for each callback. Also return false in ajax callback does not make sense so you can remove it
checkSource: function(){
var clientId = 'xxxx';
var resolve = 'http://api.soundcloud.com/resolve?url=';
$.get(resolve + this.state.text + '&client_id=' + clientId, function(data) {
$.get('http://api.soundcloud.com/users/' + data.user.id + '/?client_id=' + clientId, function(data) {
if(data.followers_count < 3000) {
this.handleSubmitClick();
}
}.bind(this));
}.bind(this));
},
Related
I am new to Knockout JS and think it is great. The documentation is great but I cannot seem to use it to solve my current problem.
The Summary of my Code
I have two viewmodels represented by two js scripts. They are unified in a parent js file. The save button's event is outside
both foreach binders. I can save all data in the details foreach.
My Problem
I need to be able to include the value from the contacts foreach binder with the values from the details foreach binder.
What I have tried
I have tried accessig the data from both viewmodels from the parent viewmodel and sending the POST request to the controller from there but the observeableArrays show undefined.
Create.CSHTML (Using MVC5 no razor)
<div id="container1" data-bind="foreach: contacts">
<input type="text" data-bind="value: contactname" />
</div>
<div data-bind="foreach: details" class="card-body">
<input type="text" data-bind="value: itemValue" />
</div>
The save is outside of both foreach binders
<div class="card-footer">
<button type="button" data-bind="click: $root.save" class="btn
btn-success">Send Notification</button>
</div>
<script src="~/Scripts/ViewScripts/ParentVM.js" type="text/javascript"></script>
<script src="~/Scripts/ViewScripts/ViewModel1.js" type="text/javascript"></script>
<script src="~/Scripts/ViewScripts/ViewModel2.js" type="text/javascript"></script>
ViewModel1
var ViewModel1 = function (contacts) {
var self = this;
self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function (contact) {
return {
contactName: contact.contactName
};
}));
}
ViewModel2
var ViewModel2 = function (details) {
var self = this;
self.details = ko.observableArray(ko.utils.arrayMap(details, function (detail) {
return {
itemNumber: detail.itemValue
};
}));
}
self.save = function () {
$.ajax({
url: baseURI,
type: "POST",
data: ko.toJSON(self.details),
dataType: "json",
contentType: "application/json",
success: function (data) {
console.log(data);
window.location.href = "/Home/Create/";
},
error: function (error) {
console.log(error);
window.location.href = "/Homel/Create/";
}
});
};
ParentViewModel
var VM1;
var VM2;
var initialContactInfo = [
{
contactPhone: ""
}
]
var initialForm = [
{
itemValue: ""
]
}
$(document).ready(function () {
if ($.isEmptyObject(VM1)) {
ArnMasterData = new ViewModel1(initialContactInfo);
ko.applyBindings(VM1, document.getElementById("container1"));
}
if ($.isEmptyObject(VM2)) {
VM2 = new ViewModel2(initialForm);
ko.applyBindings(VM2, document.getElementById("container2"));
}
});
My app returns an array of 'card' objects from an api, and displays each on the UI.
card-search.html
<div class="main-view container">
<h1>Card Search</h1>
<div id="card-search" ng-controller="cardSearchController">
<form class="search-form">
<p>Retrieve card information via name or multiverse ID</p>
<input ng-model="cardInput" type="text" name="" value="">
<select ng-model="selectedItem" ng-options="item as item.label for item in items"></select>
<button ng-click="getCard(cardInput)" type="button" name="button">Search</button>
</form>
<div class="container result-container">
<div ng-repeat="card in displayedCards" class="row display-row">
<div class="col-sm-6 card-display">
<img src={{card.imageUrl}} alt="">
</div>
<div class="col-sm-6 card-stat-display">
<p><strong>Name:</strong> {{card.name}}</p>
<p><strong>Mana Cost:</strong> {{card.manaCost}}</p>
<p><strong>Converted Mana Cost:</strong> {{card.cmc}}</p>
<p><strong>Colors:</strong> {{card.colors}}</p>
<p><strong>Type:</strong> {{card.type}}</p>
<p><strong>Text:</strong> {{card.text}}</p>
<p><strong>Flavor Text:</strong> <i> {{card.flavor}}</i></p>
<p><strong>power:</strong> {{card.power}}</p>
<p><strong>Toughness:</strong> {{card.toughness}}</p>
</div>
</div>
</div>
</div>
So this should display each card in cardDisplay, which is an array of objects.
cardSearchController.js
angular.module('mainApp').controller('cardSearchController', function($scope, mainService) {
$scope.getCard = function(searchInput) {
console.log('$scope.selectedItem.label', $scope.selectedItem.label)
if ($scope.selectedItem.label === 'Search By Multiverse ID') {
mainService.getCardById(searchInput).then(function(card){
$scope.displayedCard = card;
})
}
if ($scope.selectedItem.label === 'Search By Name') {
var searchInput = searchInput.split(' ').join('+')
mainService.getCardByName(searchInput).then(function(uniqueCards){
console.log('unique cards in controller', uniqueCards);
$scope.displayedCards = uniqueCards;
})
}
};
$scope.items = [
{
label: 'Search By Name'
},
{
label: 'Search By Multiverse ID'
}
]
});
This is the controller, the value we're trying to get displayed is
uniqueCards.
service.js
angular.module('mainApp').service('mainService', function($http,
$state) {
this.getCardByName = function(name) {
console.log(11111, 'I am here');
return $http({
method: 'GET',
url: 'https://api.magicthegathering.io/v1/cards?name=' + name + '&contains=imageUrl'
}).then(function(response) {
console.log(response.data);
var returnedCards = response.data.cards;
var uniqueCards = [];
console.log('the contents of returned cards: ', returnedCards);
for (var card of returnedCards) {
var testedCard = card;
var uniqueName = true;
for (var uniqueCard of uniqueCards) {
if (testedCard.name === uniqueCard.name) {
uniqueName = false;
break;
}
}
if (uniqueName) {
uniqueCards.push(testedCard);
}
}
console.log('here are the unique cards: ', uniqueCards);
return uniqueCards;
}),
function (cards) {
alert('An Error', cards);
};
}
This is the service. this.getCardByName should be returning uniqueCards to the controller.
So uniqueCards did get made according to console.log, but the controller isn't receiving it. I additionally receive the message from the dev console when loading the page that mainService.getCardByName isn't a function:
angular.js:14642 TypeError: mainService.getCardByName(...).then is not a function
at ChildScope.$scope.getCard (cardSearchController.js:14)
at fn (eval at compile (angular.js:15500), <anonymous>:4:223)
at callback (angular.js:27285)
at ChildScope.$eval (angular.js:18372)
at ChildScope.$apply (angular.js:18472)
at HTMLButtonElement.<anonymous> (angular.js:27290)
at HTMLButtonElement.dispatch (jquery-3.2.1.min.js:3)
at HTMLButtonElement.q.handle (jquery-3.2.1.min.js:3)
invoking getCardByName indicates that it isn't defined, though the script tag for it is in the index.html.
It's not saying getCardByName isnt a function, it's saying getCardByName.then() isn't a function. You've already executed the .then() in your mainService
I am trying to do remember me functionality using angularjs,but my email id is
storing in cookies when i click remember me and after logout when i try to
relogin,my mail id should store in username field but it was not showing
what may be the problem below is my code
HTML:
<div class="checkbox" style="margin-bottom: 0px;">
<label>
<input ng-checked="rememberMe" ng-click="rememberMe1();" type="checkbox"> Remember me
</label>
<div class="modal-footer">
<div>
<button type="submit" ng-click="submitLogin()" class="btn btn-primary btn-lg btn-block">Login</button>
</div>
<div>
my angular controller:
$scope.loginDetails = {
"email": "",
"username": "",
"password": "",
};
};
$scope.rememberMe1 = function () {
$cookies.put("emailId", $scope.loginDetails.email);
};
$scope.submitLogin = function () {
var emailId = $cookies.get("emailId"); ``
$scope.loginDetails.email = emailId;
})
}); ``
};
i believe that you'r code have so many errors and it will not even run try console.log()
solution with local storage
first in you'r service's file add Ls service
App.factory("LS", function($window, $rootScope) {
return {
setData: function (key , val) {
$window.localStorage && $window.localStorage.setItem(key , val);
return this;
},
getData: function (key) {
return $window.localStorage && $window.localStorage.getItem(key);
}
};
});
in you'r file login.js add this code
add service LS
var myMail = LS.getData('emailId');
$scope.loginDetails={
"email":"",
"username":"",
"password":""
};
$scope.rememberMe1 = function () {
LS.setData("emailId", $scope.loginDetails.email);
};
$scope.submitLogin=function(){
$scope.loginDetails.email = myMail;
};
I'm trying to implement something with jQuery and Vue.js:
And here is my script part:
<script>
function initVM(result) {
// alert(result.num)
var vm2 = new Vue({
el: '#vm2',
data: {
// ③bind one item of the result as example
rrr: result.num
}
});
$('#vm2').show();
}
$(function() {
var vm = new Vue({
el: '#vm',
data: {
content: ''
},
methods: {
submit: function(event) {
event.preventDefault();
var
$form = $('#vm'),
content = this.content.trim();
// ①post textarea content to backend
$form.postJSON('/api/parse', {
content: content
}, function(err, result) {
if (err) {
$form.showFormError(err);
}
else {
// ②receive a result dictionary
$('#vm').hide();
initVM(result);
}
});
}
}
});
});
</script>
Here is my html part:
<html>
<form id="vm", v-on="submit: submit">
<textarea v-model="content" name="content"></textarea>
<button type="submit">Have a try!</button>
</form>
<div id="vm2" style="diplay:none;">
<!-- ④show the result-->
The result:
{{ rrr }}
</div>
</html>
Here is the definition of postJSON
<script>
// ...
postJSON: function (url, data, callback) {
if (arguments.length===2) {
callback = data;
data = {};
}
return this.each(function () {
var $form = $(this);
$form.showFormError();
$form.showFormLoading(true);
_httpJSON('POST', url, data, function (err, r) {
if (err) {
$form.showFormError(err);
$form.showFormLoading(false);
}
callback && callback(err, r);
});
});
// ...
// _httpJSON
function _httpJSON(method, url, data, callback) {
var opt = {
type: method,
dataType: 'json'
};
if (method==='GET') {
opt.url = url + '?' + data;
}
if (method==='POST') {
opt.url = url;
opt.data = JSON.stringify(data || {});
opt.contentType = 'application/json';
}
$.ajax(opt).done(function (r) {
if (r && r.error) {
return callback(r);
}
return callback(null, r);
}).fail(function (jqXHR, textStatus) {
return callback({'error': 'http_bad_response', 'data': '' + jqXHR.status, 'message': 'something wrong! (HTTP ' + jqXHR.status + ')'});
});
}
</script>
The process can be described as:
Post the content to backend
Receive the result and hide the form
Create a new Vue with the result
Show the result in a div which is binding with the new Vue instance
Actually, I do receive the result successfully, which is proved by the alert(result.num) statement, but nothing find in vm2's div except The result:
Where is the problem? Or please be free to teach me a simpler approach if there is, because I don't think what I am using is a good one.
Here's questioner.
Finally I found where is the problem.
The problem lays in Mustache: {{ }}
I use jinja2, a template engine for Python and Vue.js, a MVVM frontend framework. Both of them use {{ }} as delimiters.
So if anyone got trapped in the same situation with me, which I don't think there will be, please:
app.jinja_env.variable_start_string = '{{ '
app.jinja_env.variable_end_string = ' }}' # change jinjia2 config
OR
Vue.config.delimiters = ['${', '}'] # change vue config
I am implementing a very simple React login page. I have started with the following component, Account.
var Account = React.createClass({
getInitialState: function() {
return {
showSignUp: false,
showLogin: true
}
},
update: function(data) {
this.setState(data);
},
render: function() {
if(this.state.showSignUp) {
return <SignUp/>
}
else {
return <Login update={this.update}/>
}
}
});
As expected, the Login component is displayed and renders the following:
return (
<div>
<p><input type="text" placeholder={Language.languagePack.account.username} onChange={this.usernameChange}/></p>
<p><input type="password" placeholder={Language.languagePack.account.password} onChange={this.passwordChange}/></p>
<p><a onClick={this.performLogin}>{Language.languagePack.account.login}</a></p>
<p><a onClick={this.handleSignUp}>{Language.languagePack.account.signUp}</a></p>
<p>{failedMessage}</p>
</div>
)
This all works fine. The application is picking up on the changes via the onChange hook. If the user clicks "Sign Up" though, then the following code is called:
handleSignUp: function() {
this.props.update({showSignUp: true, showLogin: false})
},
Which calls the update method in the Account class, which updates the state and causes a re-render. This is what causes it to switch to the SignUp component.
return (
<div id="signUp">
<p><input type="text" placeholder={Language.languagePack.account.username} onChange={this.usernameChange} /></p>
<p><input type="password" placeholder={Language.languagePack.account.password} onChange={this.passwordChange} /></p>
<p><input type="email" placeholder={Language.languagePack.account.email} onChange={this.emailChange} /></p>
<p><a onClick={this.handleSignUp}>{Language.languagePack.account.signUp}</a></p>
</div>
)
And for some reason, none of the events are firing on this. onChange or onClick doesn't seem to be registered. I think this is related to my implementation of switching components based on a state change that renders different components. My question is, why is this happening and what part of React have I misunderstood to make this happen?
Full Classes
Login Component
var Login = React.createClass({
getInitialState: function() {
return {
username: '',
password: '',
failed: false
}
},
usernameChange: function(event) {
this.setState({
username: event.target.value,
failed: false
});
},
passwordChange: function(event) {
this.setState({
password: event.target.value,
failed: false
});
},
performLogin: function() {
var username = this.state.username;
var password = this.state.password;
console.log("Attempting login with username " + username + " and password " + password);
var _this = this;
Api.login(username, password, function(response) {
_this.props.update({user: response, loggedIn: true});
},
function(response) {
_this.setState({failed: true});
})
},
handleSignUp: function() {
this.props.update({showSignUp: true, showLogin: false})
},
render: function() {
var failedMessage = null;
if(this.state.failed) {
failedMessage = <div className="failed-auth">{Language.languagePack.account.invalidCredentials}</div>;
}
return (
<div>
<p><input type="text" placeholder={Language.languagePack.account.username} onChange={this.usernameChange}/></p>
<p><input type="password" placeholder={Language.languagePack.account.password} onChange={this.passwordChange}/></p>
<p><a onClick={this.performLogin}>{Language.languagePack.account.login}</a></p>
<p><a onClick={this.handleSignUp}>{Language.languagePack.account.signUp}</a></p>
<p>{failedMessage}</p>
</div>
)
}
});
Signup Component
var SignUp = React.createClass({
getInitialState : function() {
return {
username: '',
password: '',
email: ''
}
},
usernameChange: function(event) {
this.setState({
username: event.target.value
});
},
passwordChange: function(event) {
this.setState({
password: event.target.value
});
},
emailChange: function(event) {
this.setState({
email: event.target.value
});
},
handleSignUp : function() {
var username = this.state.username;
var password = this.state.password;
var email = this.state.email;
console.log("Signing up with username=" + username + " and password=" + password + "and email=" + email);
},
handleLogin : function() {
console.log("Fired!");
},
render: function () {
return (
<div id="signUp">
<p><input type="text" placeholder={Language.languagePack.account.username} onChange={this.usernameChange} /></p>
<p><input type="password" placeholder={Language.languagePack.account.password} onChange={this.passwordChange} /></p>
<p><input type="email" placeholder={Language.languagePack.account.email} onChange={this.emailChange} /></p>
<p><a onClick={this.handleSignUp}>{Language.languagePack.account.signUp}</a></p>
</div>
)
}
});
Your code does work; However, I did remove references to language.LanguagePack, since that's not defined in the code you provided. If you have a javascript error, it will prevent code from running.
https://jsfiddle.net/tqz3skcr/2/
var SignUp = React.createClass({
getInitialState : function() {
return {
username: '',
password: '',
email: ''
}
},
usernameChange: function(event) {
console.log('username Changed');
this.setState({
username: event.target.value
});
},
passwordChange: function(event) {
console.log('password Changed');
this.setState({
password: event.target.value
});
},
emailChange: function(event) {
console.log('email changed');
this.setState({
email: event.target.value
});
},
handleSignUp : function() {
var username = this.state.username;
var password = this.state.password;
var email = this.state.email;
console.log("Signing up with username=" + username + " and password=" + password + "and email=" + email);
},
handleLogin : function() {
console.log("Fired!");
},
render: function () {
return (
<div id="signUp">
<p><input type="text" onChange={this.usernameChange} /></p>
<p><input type="password" onChange={this.passwordChange} /></p>
<p><input type="email" onChange={this.emailChange} /></p>
<p><a onClick={this.handleSignUp}></a></p>
</div>
)
}
});
ReactDOM.render(
<SignUp />,
document.getElementById('container')
);
I don't see anything obvious but you could try this pattern to show/hide the components. Toggle showing and hiding components in ReactJs.
First of all, make your life easier and don't use indicators like:
{
showSignUp: true,
showLogin: false
}
something like this would be much simpler and would produce less errors:
{
formToShow: "signUpForm" // or "loginForm"
}
I would say, if you start coding in this way the issue will resolve by "clean code magic" ))