In my react app I need to return a line which will be created based on a list.
Here is the object,
searchCriteria: {
op_company: "039",
doc_type: "ALL"
}
and in my UI, i need to show it as a paragraph with bold values. So the hard coded code would be like below
<p>Download request for op_company: <b>{searchCriteria.op_company}</b>, doc_type: <b>{searchCriteria.doc_type}</b></p>
But the object(searchCriteria) will be changed based on the user request. So I tried like below.
const getSearchCriteria = (criteria) => {
let searchCriteria = []
searchCriteria.push('Download request for')
Object.keys(criteria).forEach((key) => {
if(criteria[key] !== '') {
searchCriteria.push(` ${key}: ${criteria[key]},`)
}
});
return searchCriteria;
}
return (
<p>
{getSearchCriteria(searchCriteria).map((item) => <span key = {item}>{item}</span>)}
</p>
);
here i'm getting the expected output. But I can't get the value as bold (highlighted). Is there another way to directly deal with html elements?
I am using a query to receive a JSON response. I would like to loop each object (VGF, SSR, BCV, etc..) and output them to premade divs, then the arrays within those objects will loop and create divs within that matching object container.
This is a shortened down version of what I have, and it works mostly. (hopefully, I haven't screwed it up here).
The problem is I have to repeat the searchresult function by copying and pasting the entire function for each object (VGF, SSR, BCV, etc). I would really like to learn how to loop this and not have the same code pasted more than a dozen times.
If I have messed up or left something out of this question, please let me know and I will take care of it.
Here is my ajax request and javascript. I know my problem lies within this loop. I have tried to do a loop inside of a loop, etc. But, when I do that I get no results at all. I am baffled and ready to learn.
$(function getData() {
$("#searchbtn").click(function () {
$.ajax({
url: "action.php",
type: "POST",
data: {},
dataType: "json",
success: function (response) {
console.log(response);
searchresult(response);
}
});
});
});
let searchresult = function(response) {
let container = document.getElementById('VGFresults');
let output = "";
for (let j = 0; j < response.length; j++) {
if (response[j].rcode == "VGF") {
output +=
`<div id="person${response[j].code}">
<p>${response[j].firstname} ${response[j].lastname}</p>
</div>`
}
$(container).html(output);
}
};
Here is my response (Same layout as I am currently receiving but shortened the objects in the arrays).
response =
{"VGF":
[{"code":"TU","rcode":"VGF","firstname":"Tom","lastname":"Riddle"},
{"code":"AZ","rcode":"VGF","firstname":"Harry","lastname":"Potter"},
{"code":"FR","rcode":"VGF","firstname":"Hermoine","lastname":"Granger"}],
"SSR":
[{"code":"HG","rcode":"SSR","firstname":"Walt","lastname":"Disney"},
{"code":"TR","rcode":"SSR","firstname":"H.R.","lastname":"Pickins"},
{"code":"ED","rcode":"SSR","firstname":"Tom","lastname":"Ford"}],
"BCV":
[{"code":"YH","rcode":"BCV","firstname":"Tom","lastname":"Clancy"},
{"code":"RS","rcode":"BCV","firstname":"Robin","lastname":"Williams"},
{"code":"AB","rcode":"BCV","firstname":"Brett","lastname":"Favre"}]}
Here is the HTML that the searchresult function is working with. Currently, it works fine.
To clarify, I would like each object to insert its arrays within the corresponding div. Example:
SSR arrays will go into <div id="SSRresults">
BCV arrays will go into <div id="BCVresults">
From there, each array will create a div within that *results div for each array.
<div id="VGFresults">
<div id="VGFheader">This is the VGF Header</div>
<div id="VGFresults">The Javascript Creates Divs for each array here.</div>
</div>
<div id="SSRresults">
<div id="SSRheader">This is the SSR Header</div>
<div id="SSRresults">The Javascript Creates Divs for each array here.</div>
</div>
<div id="BCVresults">
<div id="BCVheader">This is the BCV Header</div>
<div id="BCVresults">The Javascript Creates Divs for each array here.</div>
</div>
Thanks, any help is much appreciated.
I would do like this:
I declare the response as variable (but sure it will work with your ajax response.
var response =
{"VGF":
[{"code":"TU","rcode":"VGF","firstname":"Tom","lastname":"Riddle"},
{"code":"AZ","rcode":"VGF","firstname":"Harry","lastname":"Potter"},
{"code":"FR","rcode":"VGF","firstname":"Hermoine","lastname":"Granger"}],
"SSR":
[{"code":"HG","rcode":"SSR","firstname":"Walt","lastname":"Disney"},
{"code":"TR","rcode":"SSR","firstname":"H.R.","lastname":"Pickins"},
{"code":"ED","rcode":"SSR","firstname":"Tom","lastname":"Ford"}],
"BCV":
[{"code":"YH","rcode":"BCV","firstname":"Tom","lastname":"Clancy"},
{"code":"RS","rcode":"BCV","firstname":"Robin","lastname":"Williams"},
{"code":"AB","rcode":"BCV","firstname":"Brett","lastname":"Favre"}]}
let searchresult = function(response) {
// let container = document.getElementById('VGFresults');
let output = "";
for (var key in response) {
// skip loop if the property is from prototype
if (!response.hasOwnProperty(key)) continue;
var obj = response[key];
let container = document.getElementById(key+'results');
for (var prop in obj) {
// skip loop if the property is from prototype
if (!obj.hasOwnProperty(prop)) continue;
// your code
//alert(prop + " = " + obj[prop]);
console.log(obj[prop])
output += "<div id="+prop+"><p>"+obj[prop].firstname+" "+ obj[prop].lastname+"</p></div>"
}
}
container.innerText = output;
console.log(output);
};
<div id="VGFresults"></div>
each property VGF, SSR, BCV and so on can be handled now.
EDIT: based on users request, I guess you can edit the selector like this:
let container = document.getElementById(key+'results');
I'm clicking a table row to edit the fields in a modal. The modal must have 2 functionalities (Add or Edit) depending on the GET request data like below.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
}
HTML
<label ng-if="editedObject.email">{{editedObject.email}}</label>
<label ng-if="!editedObject.email">Email</label>
<input ng-model="newObject.email" />
I am able to display the object in the labels, but that's not much help, because the data needs to be shown in the input boxes to be Edited and Saved.
How can i show the data from editedObject.email in the input, so i can save it using newObject.email?
I tried ng-init="editedObject.email", but it doesn't work. Is there some other ng-something that does this or i should be doing it in another way?
Update:
Edit and Update Methods, both are in the mainController.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
})
}
//Controller for the Modal
function DialogController($scope, $mdDialog, editedObject) {
$scope.editedObject = editedObject
$scope.submitObject = function(newObject) {
$http.post('/api/interview', newObject)
}
}
You have to make a deep copy from editObject.email to newObject.email. This could be done this way in controller after editOject.email has a value assigned.
$scope.newObject.email = angular.copy($scope.editObject.email);
My HTML structure is this:
<li ng-repeat="m in members">
<div class="col-name">{{m.name}}</div>
<div class="col-trash">
<div class="trash-button"></div>
</div>
</li>
What I want to be able to do is using protractor, click on the trash when m.name equals a specific value.
I've tried things like:
element.all(by.repeater('m in members')).count().then(function (number) {
for (var i = 0 ; i < number ; i++) {
var result = element.all(by.repeater('m in members').row(i));
result.get(0).element(by.binding('m.name')).getAttribute('value').then(function (name) {
if (name == 'John') {
result.get(0).element(by.className('trash-button')).click();
};
});
};
});
This seems like it should work, however, it seems like my function does not even run this.
I've also looked into promises and filters though have not been successful with those either. Keep getting errors.
var array = element.all(by.repeater('m in members'));
array.filter(function (guy) {
guy.getText().then(function (text) {
return text == 'John';
})
}).then(function (selected) {
selected.element(by.className('trash-button')).click()
}
All I would like to do is click on the corresponding trash when looking for a specific member list!
Any help would be much appreciated.
EDIT: suggested I use xpath once I find the correct element, which is fine, the problem is I cannot get the filter function's promise to let me use element(by.xpath...)
If I try:
var array = element.all(by.repeater('m in members'));
array.filter(function (guy) {
guy.getText().then(function (text) {
return text == 'John';
})
}).then(function (selected) {
selected.element(by.xpath('following-sibling::div/div')).click()
}
I get the error:
Failed: Object has no method 'element'
Figured it out. Following the Protractor filter guideline in the API reference and using alecxe's xpath recommendation, this code will click on any element you find after filtering it.
element.all(by.className('col-name')).filter(function (member, index) {
return member.getText().then(function (text) {
return member === 'John';
});
}).then( function (elements) {
elements[0].element(by.xpath('following-sibling::div/div/')).click();
});
You can change the xpath to select different stuff incase your HTML does not look like mine.
It looks like you can avoid searching by repeater, and use by.binding directly. Once you found the value you are interested in, get the following sibling and click it:
element.all(by.binding('m.name')).then(function(elements) {
elements.filter(function(guy) {
guy.getText().then(function (text) {
return text == 'John';
})
}).then(function (m) {
m.element(by.xpath('following-sibling::div/div')).click();
});
});
Or, a pure xpath approach could be:
element(by.xpath('//li/div[#class="col-name" and .="John"]/following-sibling::div/div')).click();
In working with the API from themoviedb.com, I'm having the user type into an input field, sending the API request on every keyup. In testing this, sometimes the movie poster would be "null" instead of the intended poster_path. I prefer to default to a placeholder image to indicate that a poster was not found with the API request.
So because the entire poster_path url is not offered by the API, and since I'm using an AngularJS ng-repeat, I have to structure the image tag like so (using dummy data to save on space):
<img ng-src="{{'http://example.com/'+movie.poster_path}}" alt="">
But then the console gives me an error due to a bad request since a full image path is not returned. I tried using the OR prompt:
{{'http://example.com/'+movie.poster_path || 'http://example.com/missing.jpg'}}
But that doesn't work in this case. So now with the javascript. I can't seem to get the image source by using getElementsByTagName or getElementByClass, and using getElementById seems to only grab the first repeat and nothing else, which I figured would be the case. But even then I can't seem to replace the image source. Here is the code structure I attempted:
<input type="text" id="search">
<section ng-controller="movieSearch">
<article ng-repeat="movie in movies">
<img id="myImage" src="{{'http://example.com/'+movie.poster_path}}" alt="">
</article>
</section>
<script>
function movieSearch($scope, $http){
var string,
replaced,
imgSrc,
ext,
missing;
$(document).on('keyup', function(){
string = document.getElementById('search').value.toLowerCase();
replaced = string.replace(/\s+/g, '+');
$http.jsonp('http://example.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
console.dir(data.results);
$scope.movies = data.results;
});
imgSrc = document.getElementById('myImage').src;
ext = imgSrc.split('.').pop();
missing='http://example.com/missing.jpg';
if(ext !== 'jpg'){
imgSrc = missing;
}
});
}
</script>
Any ideas with what I'm doing wrong, or if what I'm attempting can even be done at all?
The first problem I can see is that while you are setting the movies in a async callback, you are looking for the image source synchronously here:
$http.jsonp('http://domain.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
console.dir(data.results);
$scope.movies = data.results;
});
// This code will be executed before `movies` is populated
imgSrc = document.getElementById('myImage').src;
ext = img.split('.').pop();
However, moving the code merely into the callback will not solve the issue:
// THIS WILL NOT FIX THE PROBLEM
$http.jsonp('http://domain.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
console.dir(data.results);
$scope.movies = data.results;
// This will not solve the issue
imgSrc = document.getElementById('myImage').src;
ext = img.split('.').pop();
// ...
});
This is because the src fields will only be populated in the next digest loop.
In your case, you should prune the results as soon as you receive them from the JSONP callback:
function movieSearch($scope, $http, $timeout){
var string,
replaced,
imgSrc,
ext,
missing;
$(document).on('keyup', function(){
string = document.getElementById('search').value.toLowerCase();
replaced = string.replace(/\s+/g, '+');
$http.jsonp('http://domain.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
console.dir(data.results);
$scope.movies = data.results;
$scope.movies.forEach(function (movie) {
var ext = movie.poster_path && movie.poster_path.split('.').pop();
// Assuming that the extension cannot be
// anything other than a jpg
if (ext !== 'jpg') {
movie.poster_path = 'missing.jpg';
}
});
});
});
}
Here, you modify only the model behind you view and do not do any post-hoc DOM analysis to figure out failures.
Sidenote: You could have used the ternary operator to solve the problem in the view, but this is not recommended:
<!-- NOT RECOMMENDED -->
{{movie.poster_path && ('http://domain.com/'+movie.poster_path) || 'http://domain.com/missing.jpg'}}
First, I defined a filter like this:
In CoffeeScript:
app.filter 'cond', () ->
(default_value, condition, value) ->
if condition then value else default_value
Or in JavaScript:
app.filter('cond', function() {
return function(default_value, condition, value) {
if (condition) {
return value;
} else {
return default_value;
}
};
});
Then, you can use it like this:
{{'http://domain.com/missing.jpg' |cond:movie.poster_path:('http://domain.com/'+movie.poster_path)}}