I have a problem with some dynamic data that it is stored in database.
I am storing in database div with ng-style, and then when response is back from server with this div , will like to apply a style to this div.
If it is not dynamic, I have no problems.
this is my code:
This my static html.
<div ng-controller="empty" >
<div>
<div ng-bind-html="validData | unsafe"/>
</div>
</div>
this is comming from database.
<div class="row">
<div ng-style="visualization" class="col-md-4">.col-md-2</div>
<div ng-style="visualization" class="col-md-8">.col-md-8</div>
</div>
<div class="row">
<div ng-style="visualization" class="col-md-4">.col-md-8</div>
</div>
and this should be my controller.
$http.get(globalVars + 'page/' + lastParam)
.success(function (data) {
$scope.empty = data;
$scope.validData = $scope.empty.layout.schema;
$compile($scope.validData);
if(typeof $rootScope.mode == 'undefined' || $rootScope.mode =='edit'){
$scope.visualization = {
"border-style": "dashed"
}
}
else{
$scope.visualization = {
"border-style": "none"
}
}
})
.error(function (data) {
});
in theory, in each div from data coming from database should be added "style=border-style:none/dashed",but this not happening, so ng-style it is not binded to angular.
some help should be appreciated.
thanks
The $compile(html) function returns another function to which you can pass the $scope variable. You could try doing:
$scope.validData = $compile($scope.validData)($scope);
This could make your controller code look like:
$http.get(globalVars + 'page/' + lastParam).success(function (data) {
$scope.empty = data;
$scope.validData = $scope.empty.layout.schema;
if(typeof $rootScope.mode == 'undefined' || $rootScope.mode =='edit'){
$scope.visualization = {
"border-style": "dashed"
}
}else{
$scope.visualization = {
"border-style": "none"
}
}
$scope.validData = $compile($scope.validData)($scope);
}).error(function (data) {
});
However there are other ways of doing what you're trying to achieve, possibly using CSS. For example, place a conditional class using ng-class, on the outer div:
<div ng-class="{'edit-mode': editModeEnabled }" ng-bind-html="validData | unsafe"/>
Then in CSS:
.edit-mode .row > div {
border-style: dashed;
}
And set editModeEnabled in your controller:
$scope.editModeEnabled = $rootScope.mode === 'edit';
Thanks, I used your suggestion.
div ng-class="{'edit-mode': editModeEnabled }" ng-bind- html="validData | unsafe"/>
Then in CSS:
.edit-mode .row > div {
border-style: dashed;
}
regards
Related
Every time a selection is made from a dropdown menu, specific data is pulled from facebook and added to different divs. I am trying to update the contents of the div every time a different selection is made, however at the minute, the contents are just appended on after the initial contents.
This is the code that gets data based on a selection and creates the list from the returned data
<script>
city = document.getElementById("citySelection")
city.addEventListener("change", function() {
var selected = this.value;
var eventsList = document.getElementById("events");
if (selected == "None") {
eventsList.style.display = "none";
} else {
eventsList.style.display = "block";
};
if (selected == 'Bristol') {
getBristolEvents();
};
if (selected == 'Leeds') {
getLeedsEvents();
};
if (selected == 'Manchester') {
getManchesterEvents();
};
if (selected == 'Newcastle') {
getNewcastleEvents();
};
});
function createList(response, listId) {
var list = document.createElement('UL')
for (var i = 0; i < 10; i++) {
var events = response.data[i].name
var node = document.createElement('LI');
var textNode = document.createTextNode(events);
node.appendChild(textNode);
list.appendChild(node)
listId.appendChild(list);
}};
</script
This is the div being targeted:
<html>
<div id="events" style="display: none">
<div id="eventsDiv" style="display: block">
<div id="eventsListOne">
<h3 id='headerOne'></h3>
</div>
<div id="eventsListTwo">
<h3 id='headerTwo'></h3>
</div>
<div id="eventsListThree">
<h3 id='headerThree'></h3>
</div>
</div>
</div>
</div>
</html>
I have tried resetting the innerHtml of the div every time the function to get the data from facebook is called:
<script>
function getEventsThree(fbUrl, title) {
var listId = document.getElementById('eventsListThree');
var headerThree = document.getElementById('headerThree');
listId.innerHtml = "";
headerThree.append(title)
FB.api(
fbUrl,
'GET', {
access_token
},
function(response) {
listId.innerHtml = createList(response, listId)
}
)};
</script>
However, that still doesn't reset the contents of the div.
I've looked at other response but they all use jquery which I am not using.
Can anyone advise on the best way to fix this? Thanks.
I think your Hennessy approach is fine. Generate the inner content, then set .innerHTML.
At least one of your problems, maybe the only one, appears to be that you set .innerHTML to the return value of createList, but that function does not return anything.
I'm using a "GET" request to retrieve information from this API
The "GET"request is fine, but some objects don't have image thumbnails to put as my source, and I want to filter them out, but can't seem to know where to put that method, here is my code
$(document).ready(function(){
$('button').on('click', function(event){
event.preventDefault();
$('#result').empty();
var userInput = $('input').val()
$.ajax({
method:"GET",
url:"https://www.reddit.com/r/" + userInput + ".json?jsonp",
success:success
})
})
function success(response){
var result ="";
var zero = "0"
$.each(response, function(index, value){
var list = response.data.children
$.each(list.slice(1).slice(0, 12), function(index,value){
var thumbnail = value.data.thumbnail
result += "<li>" + "<img src='" + thumbnail + "'/>"
$('#result').html(result)
})
})
}
})
Also if you have any idea how to structure my code so I only need to make one $.each loop, that would be help also!
Thanks a tonne,
James
Filter out the item with falsy thumbnail in the list (null or undefined, among others) by using filter
var list = response.data.children.filter(function(item) {
return item.data.thumbnail;
});
$.each(list, function(index,value){
var thumbnail = value.data.thumbnail;
$('#result').html(result)
})
Promises will help you to have a more structured code,
Array.prototype.reduce will help you to avoid unnecessary iterations.
function loadRedditData(keyword) {
return jQuery
.get(`https:\/\/www.reddit.com\/r\/${keyword}.json`, {jsonp: ''})
.then(res => res.data.children.slice(1, 12))
.then(data => (
data.reduce((html, item) => {
let card = `<h5>${item.data.name}</h5>`;
if(item.data.thumbnail) {
card = `<img src="${item.data.thumbnail}" />`;
}
return html.concat(`<div class="card">${card}</div>`);
}, '')
))
.then(html => jQuery('#result').html(html))
;
}
$(document).ready(function() {
$('button').click(function() {
return loadRedditData(jQuery('input').val() || 'Ecmascript 6');
});
})
#result {
border: 1px solid cyan;
margin: 5px;
padding: 5px;
min-height: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Load Your Data</button>
<input value="javascript" />
<hr />
<section id="result"></section>
I'm stuck on a basic thing, but which gets very complex with Polymer. I would like to change the text color of a table cell according to the value in it. I've tried using filter in dom-repeat, but it doesn't work because I don't know how to access HTML this way.
Here's sample code:
<h4>[[propertiesList.length]] Properties available</h4>
<paper-card elevation="1">
<div class="tableRow title">
<div class="title colM">Name</div>
<div class="title colL">URL</div>
<div class="title colM">Owned by</div>
<div class="title colS">Created</div>
<div class="title colM">Videos count</div>
<div class="title colM">Status</div>
<div class="title colXS">Edit</div>
</div>
<template is="dom-repeat" items="[[propertiesList]]" filter="StatusColor">
<div class="tableRow">
<div class="colM">[[item.name]]</div>
<div class="colL">[[item.url]]</div>
<div class="colM">[[item.user.name]]</div>
<div class="colS">[[item.created]]</div>
<div class="colM">[[item.videos_count]]</div>
<div class="colM" id="status">[[item.status.label]]</div>
<div class="colXS left"><paper-icon-button class="editIcon" on-tap="editProperty" icon="mdi:pencil"></paper-icon-button></div>
</div>
</template>
</paper-card>
and the JS:
StatusColor: function (item) {
if (item.status.label == "Active") {
document.getElementById("status").style.color = '#48C8B6';
console.log("Property is active");
return item.status.label;
}
},
...doesn't do anything to my text color.
Then, I've tried a good old for-loop, but for some reason, I can't get the .length value right. Here's the same HTML as above minus the filter, and "status" is now a class instead of id. The JS is as follows:
attached: function () {
this.async(function () {
var status = document.getElementsByClassName("status");
console.log("Status value : ", status);
var count = status.length;
console.log("count value : ", count);
for (i = 0; i < count; i++) {
var text = status[i].innerText;
if (text == "Active") {
status[i].style.color = "#48C8B6";
} else {
status[i].style.color = "#F1412E";
}
}
});
My first console.log that shows the status value is right. I get all my "status" divs, and the length property in Chrome Dev Tools is the right one, but the second console.log (the "count" one) always displays 0. Thus, I can't make my for-loop work properly.
Help me (...obiwan kenobi)
Note that the template filter is intended for filtering out items from your repeater (not for mapping items as you attempted to do). Also, the template repeater invokes the filter callback before stamping an item. On the first iteration, the #status node will not have been stamped yet, so document.getElementById('status') would return null (assuming no other node with ID of status exists already), resulting in a TypeError and nothing rendered for that template repeater.
Instead of the template filter or the attached callback, I recommend the following:
CSS styles for default and active statuses (keep behavioral logic in JS, and styles in CSS)
Conditionally assigned class for status div (using a computed binding with attribute binding)
As in:
// style
.status {
color: #F1412E;
}
.status.active {
color: #48C8B6;
}
// template ($= for native attribute binding)
<div class$="[[_computeStatusStyle(item.status.label)]]">[[item.status.label]]</div>
// script
Polymer({
_computeStatusStyle: function(label) {
var baseStyle = "colM status";
var activeStyle = label === "Active" ? " active" : "";
return baseStyle + activeStyle;
}
});
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="paper-card/paper-card.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<style>
paper-card {
width: 100%;
}
.tableRow {
margin: 1rem;
border-bottom: solid 1px lightgray;
}
.status {
color: #F1412E;
}
.status.active {
color: #48C8B6;
}
</style>
<template>
<h4>[[propertiesList.length]] Properties available</h4>
<paper-card elevation="1">
<template is="dom-repeat" items="[[propertiesList]]">
<div class="tableRow">
<div class="colM">[[item.name]]</div>
<div class="colL">[[item.url]]</div>
<div class="colM">[[item.user.name]]</div>
<div class="colS">[[item.created]]</div>
<div class="colM">[[item.videos_count]]</div>
<div class$="[[_computeStatusStyle(item.status.label)]]">[[item.status.label]]</div>
<div class="colXS left">
<paper-icon-button class="editIcon" on-tap="editProperty" icon="mdi:pencil"></paper-icon-button>
</div>
</div>
</template>
</paper-card>
</template>
<script>
HTMLImports.whenReady(function() {
"use strict";
Polymer({
is: 'x-foo',
properties: {
propertiesList: {
type: Array,
value: generateProperties
}
},
_computeStatusStyle: function(label) {
var baseStyle = "colM status";
var activeStyle = label === "Active" ? " active" : "";
return baseStyle + activeStyle;
}
});
/** Value generator for <x-foo>.propertiesList above */
function generateProperties() {
var props = [];
for (var i = 0; i < 5; i++) {
var statusLabel = i % 2 == 0 ? 'Active' : 'Inactive';
props.push(new Property('name', 'url', 'username', 'created', 'videoCount', statusLabel));
}
return props;
}
/** Property class for <x-foo>.propertiesList above */
function Property(name, url, username, created, videoCount, label) {
this.name = name;
this.url = url;
this.user = {};
this.user.name = username;
this.created = created;
this.videos_count = videoCount;
this.status = {};
this.status.label = label;
};
});
</script>
</dom-module>
</body>
codepen
How can i pass html through in AngularJS controller ?
Here is my list.html:
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({{item.iCompanyID}},'{{item.vCompanyName}}')" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
<div id="packagehtml"></div>
</div>
<div id="lp" class="col-md-12 listing-div hidden"></div>
in controller.js:
$scope.pData = [];
$scope.getPackageInfo = function(id,name) {
$scope.name = name;
var summery = SubscriptionoptioncompanylistFactory.getSummary(id);
document.getElementById("lp").classList.remove("hidden");
$('.packages-data').html('');
$('#loading').show();
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
if(data != 0) {
$("#lp").html(summery); // this is used to append the data
document.getElementById("np").classList.add("hidden");
Array.prototype.push.apply($scope.pData, data);
$('#loading').hide();
} else {
document.getElementById("lp").classList.add("hidden");
document.getElementById("np").classList.remove("hidden");
$('#loading').hide();
}
});
};
Here, I have wrote $("#lp").html(summery);, in that div I have to append html which comes from var summery = SubscriptionoptioncompanylistFactory.getSummary(id);. But this is not going to append the data. In console I can see that data comes in summary variable. How can I do?
have a look at below modifications
Use angular ng-show for showing/hiding elements
Use data binding and avoid Jquery like Dom manipulation
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({{item.iCompanyID}},'{{item.vCompanyName}}')" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
<div id="packagehtml"></div>
</div>
<div id="lp" ng-show="lbVisible" class="col-md-12 listing-div hidden">{{summaryBinding}}</div>
and the controller would look like :
$scope.pData = [];
$scope.getPackageInfo = function (id, name) {
$scope.name = name;
var summery = SubscriptionoptioncompanylistFactory.getSummary(id);
$scope.lbVisible = true; //document.getElementById("lp").classList.remove("hidden");
$('.packages-data').html('');
$scope.loadingVisible = true; //$('#loading').show();
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function (data) {
if (data != 0) {
$scope.summaryBinding = summery; // $("#lp").html(summery); // this is used to append the data
$scope.npVisible = false; // document.getElementById("np").classList.add("hidden");
Array.prototype.push.apply($scope.pData, data);
$scope.loadingVisible = false; // $('#loading').hide();
} else {
$scope.lbVisible = false; //document.getElementById("lp").classList.add("hidden");
$scope.npVisible = false; //document.getElementById("np").classList.remove("hidden");
$scope.loadingVisible = false; // $('#loading').hide();
}
});
};
your snippet is not showing elements that you use :
np, #loading so just find them and add the `ng-show` with the proper scope variable : `npVisible , lbVisible , loadingVisible`
and note that we add the data using summaryBinding
hope this helps :)
I have a reactJS component that looks like this :
var LikeCon = React.createClass({
render(){
return this.renderLikeButton(this.props.like, this.props.likeCount)
},
renderLikeButton(like, likeCount){
var content;
var tmpLikeCount;
if(likeCount < 1){
tmpLikeCount = "";
}
else{
tmpLikeCount = likeCount;
}
if(like == 1){
content = <div className="likeButConAct"><div className="likeB"> </div><div className="likeCount">{tmpLikeCount}</div></div>
}
else{
content = <div className="likeButCon"><div className="likeB"> </div><div className="likeCount">{tmpLikeCount}</div></div>
}
return content;
}
});
Say that I want to hide the likeCount element if there is no likes. How do I do this as simple as possible? I donĀ“t want another component to render this.
If your variable is null or undefined then React simply won't render it. That means your conditional code can be as simple as:
var tmpLikeCount;
if(likeCount >= 1){
tmpLikeCount = likeCount;
}
But I think you can make your code even simpler using class sets:
http://facebook.github.io/react/docs/class-name-manipulation.html
var LikeCon = React.createClass({
render(){
var likeCountCmp;
var classes = React.addons.classSet({
likeButCon: true,
active: this.props.like
});
if(this.props.likeCount > 0) {
likeCountCmp = <div className="likeCount">{this.props.likeCount}</div>;
}
return (
<div className={classes}>
<div className="likeB"> </div>
{likeCountCmp}
</div>
)
}
});
A final variation that I think will work is to use an implicit function return:
var LikeCon = React.createClass({
render(){
var classes = React.addons.classSet({
likeButCon: true,
active: this.props.like
});
return (
<div className={classes}>
<div className="likeB"> </div>
{this.getLikeCountCmp()}
</div>
)
},
getLikeCountCmp: function() {
if(this.props.likeCount > 0) {
return <div className="likeCount">{this.props.likeCount}</div>;
}
}
});
if we don't specifically return anything from getLikeCountCmp, we end up with undefined, which React renders as nothing.
Note that I'm a bit confused with your like == 1 comparison - should that be true/false rather than a number? I've assumed this.props.like will be true or false in my examples. That means it'd be called with:
<LikeCon like={true|false} likeCount={5} />
If you like to put everything inline, you can do this:
renderLikeButton(like, likeCount){
return (<div className={like==1 ? "likeButConAct" : "likeButCon" }>
<div className="likeB"> </div>
{ likeCount > 0 ? <div className="likeCount">{likeCount}</div>: null }
</div>);
}
That way you wont be rendering .likeCount div if likeCount is 0.
jsFiddle: http://jsfiddle.net/715u9uvb/
what about using the className to hide the element?
something like :
var cssClasses = "likeButConAct ";
if ( likeCount < 1 ) {
cssClasses += "hidden";
}
...
return <div className=cssClasses><div ...
EDIT
var content;
var tmpLikeCount;
var likeCounterComponent;
if(likeCount > 0){
likeCounterComponent = <div className="likeCount">{likeCount}</div>
}
if(like == 1){
cssClasses = "likeButConAct"
}
else{
cssClasses = "likeButCon";
}
return (
<div className=cssClasses>
<div className="likeB"> </div>
{ likeCounterComponent }
</div>);
You can add the likeCounter only if there are likes. If there are likes the likeCounterComponent contains the JSX code to render the likes counter, otherwise is undefined and therefore nothing will be rendered.
I haven't tried to run the code, but I guess you got the idea to solve this problem. :D
Colin's answer looks good to me.. if your issue is with having aspects of rendering extracted to a separate function, you don't HAVE to do that. This works too:
return (
<div className={classes}>
<div className="likeB"> </div>
{this.props.likeCount > 0 && (
<div className="likeCount">{this.props.likeCount}</div>
)};
</div>
)
....
if (likeCount < 1) {
return "";
}
....