How I can optimize my HTML markup? In this case (I use Sublime Text 2), I choose "set syntax JSX" for highlighting and emeet won't work at first.
At second - more preferable for me, to keep markup in some .tmpl files.
It is possible in this case? For example, my render method:
render: function() {
var result = this.state.data;
var self = this;
var inputNodes = result.map && result.map(function(item, keyIndex) {
return (
<div className="row" key={keyIndex} className={'inputs-row ' + (item.disabled ? 'inputs-row_disabled':'')}>
<div className="col-md-12">
<div className="col-md-6 form-group">
<div className="input-group">
<div className="input-group-addon">
<i className="fa fa-info fa-fw"></i>
</div>
<input className="key-input form-control" type='text' value={item.name} onClick={self.onInputKeyClick.bind(self,item)} readOnly />
</div>
</div>
{
item.values.map(function(value, valIndex) {
return (
<div className="col-md-6 form-group" key={valIndex}>
<div className="input-group">
<input className="key-input form-control" type='text' value={value.name} onChange={self.changeLocalizedValue.bind(self, value, valIndex, keyIndex)} />
<div className="input-group-addon input-group-addon_btn">
<button className="btn btn-default btn_right-radius" onClick={self.sendItem.bind(self, value)}>
<i className="fa fa-check fa-fw"></i>
</button>
</div>
</div>
</div>
)
})
}
</div>
</div>
);
});
return (
<div>
<div>{inputNodes}</div>
<button onClick={self.sendAll}>SEND ALL</button>
</div>
)
}
P.S. I use: gulp and browserify.
There are libraries that lets you extract React templates into their own files, but I think one of the strengths of React is that the markup is co-located with the view logic. If the markup is changed then the view logic often has to be changed, and vice versa. Keeping them in the same file makes that more convienient.
I would recommend you to create more components. Take this chunk of JSX for example:
<div className="col-md-6 form-group">
<div className="input-group">
<div className="input-group-addon">
<i className="fa fa-info fa-fw"></i>
</div>
<input className="key-input form-control" type='text' value={item.name} onClick={self.onInputKeyClick.bind(self,item)} readOnly />
</div>
</div>
Does very little, and it's not very readable what the purpose of that chunk is. If you instead extract that into another component and give it a meaningful name, your markup won't look as cluttered, and you get better readability.
Related
<div className="col-md-12">
<div className="row">
{shopeeship.map(function (key,value) {
if(key.enabled){
console.log("yes");
<div className="col-md-6">
<div className="form-group">
<span className="mr-4 pr-4">
<IntlMessages id="shopee.poswm" />
</span>
<label className="pull-right" title="">
<Switch/>
</label>
</div>
</div>
}})}
</div>
</div>
I have some data and want to loop through it to render some UI. In the above code I tried to loop the data and I checked that if the key enabled then to echo the html value. It successfully prints yes in console log but the html does not render as expected. Anyone has faced such an issue before? Please help.
It's because you forgot to return your html from loop
Do this
<div className="col-md-12">
<div className="row">
{shopeeship.map(function (key,value) {
if(key.enabled){
console.log("yes");
return(
<div className="col-md-6">
<div className="form-group">
<span className="mr-4 pr-4">
<IntlMessages id="shopee.poswm" />
</span>
<label className="pull-right" title="">
<Switch/>
</label>
</div>
</div>
)
}})}
</div>
</div>
You are not returning from map, you can use arrow function instead for implicit return as
<div className="col-md-12">
<div className="row">
{shopeeship.map((key,value) => key.enabled &&
(<div className="col-md-6">
<div className="form-group">
<span className="mr-4 pr-4">
<IntlMessages id="shopee.poswm" />
</span>
<label className="pull-right" title="">
<Switch/>
</label>
</div>
</div>)
)}
</div>
</div>
Hope it helps
you need to return the html part, map creates a new array and expects a return value else your array will be filled with null values, hence you would need to return the said html part.
Try this simplified solution using ternary condition and arrow function.
<div className="col-md-12">
<div className="row">
{shopeeship.map((key,value)=> key.enabled ?
<div className="col-md-6" key={value}>
<div className="form-group">
<span className="mr-4 pr-4">
<IntlMessages id="shopee.poswm" />
</span>
<label className="pull-right" title="">
<Switch/>
</label>
</div>
</div>
:null)}
</div>
</div>
Not sure if I am phrasing this correctly.
I have an observableArray and I can add to that array from an input and also remove the list item. but if I modify the created item I lose the connection to the array. How can I keep the binding to the array?
Fiddle Attached
HTML
<div class="group-settings-container mt-4">
<div class="row">
<div class="col-md-3">
<h4><i class="fas fa-object-group"></i> Create Groups</h4>
</div>
<div class="col-md-6">
<div class="input-group">
<input type="text" class="form-control create-group-name" data-bind="value: groupItemToAdd, valueUpdate: 'afterkeydown' " placeholder="Enter group name" value="">
<div class="input-group-append">
<button class="btn btn-primary add-group-btn" data-bind="click: addGroupItem, enable: groupItemToAdd().length > 0" type="button"><i class="fas fa-plus"></i>
Add group</button>
</div>
</div>
</div>
<div class="create-groups-container mb-4">
<ul class="list-group create-group-list my-2" data-bind="foreach: allGroupItems">
<li class="list-group-item">
<div class="input-group">
<input type="text" class="form-control created-group-input" data-bind="value: $data">
<div>
<button class="btn btn-danger remove-group-item-btn" data-bind="click: $parent.removeSelectedGroupItem" type="button"><i class="fas fa-times"></i>
Remove</button>
</div>
</div>
</li>
</ul>
</div>
<!-- end create groups container -->
</div>
<!-- end group settings container -->
JS
function ViewModel() {
var self = this;
self.groupItemToAdd = ko.observable("");
self.allGroupItems = ko.observableArray([]);
self.addGroupItem = function() {
if ((self.groupItemToAdd() != "") && (self.allGroupItems.indexOf(self.groupItemToAdd()) < 0)) {
self.allGroupItems.push(self.groupItemToAdd());
}
self.groupItemToAdd(""); // clear the input
}
self.removeSelectedGroupItem = function(index) {
// self.allGroupItems.splice(index, 1);
// console.log(self.allGroupItems.splice(index, 1));
self.allGroupItems.remove(index);
}
}
// end ViewModel
ko.applyBindings(new ViewModel());
You have an observableArray. Which means, any changes to the array are tracked and updated. The items inside it are just strings. They are not observables. Any changes you make from the UI is not updated back to the view model. This behaviour is not limited to strings. The same thing applies if you have an observableArray of regular javascript object literals.
From the documentation:
Simply putting an object into an observableArray doesn’t make all of that object’s properties themselves observable. Of course, you can make those properties observable if you wish, but that’s an independent choice. An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.
So, instead of adding strings to the observableArray, you can push an object with an observable property to the observableArray. Now the changes to item property are tracked. It's important to make the property an observable, otherwise you'll run into the same issue.
function ViewModel() {
var self = this;
self.groupItemToAdd = ko.observable("");
self.allGroupItems = ko.observableArray([]);
self.addGroupItem = function() {
if (self.groupItemToAdd() && !self.allGroupItems().some(a => a.item() === self.groupItemToAdd())) {
self.allGroupItems.push({
item: ko.observable(self.groupItemToAdd())
});
}
self.groupItemToAdd(""); // clear the input
}
self.removeSelectedGroupItem = function(index) {
self.allGroupItems.remove(index);
}
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<div class="group-settings-container mt-4">
<div class="row">
<div class="col-md-3">
<h4><i class="fas fa-object-group"></i> Create Groups</h4>
</div>
<div class="col-md-6">
<div class="input-group">
<input type="text" class="form-control" data-bind="value: groupItemToAdd, valueUpdate: 'afterkeydown' " placeholder="Enter group name">
<div class="input-group-append">
<button class="btn btn-primary add-group-btn" data-bind="click: addGroupItem, enable: groupItemToAdd().length > 0" type="button">Add group</button>
</div>
</div>
</div>
<ul class="list-group create-group-list my-2" data-bind="foreach: allGroupItems">
<li class="list-group-item">
<div class="input-group">
<input type="text" class="form-control created-group-input" data-bind="value: item">
<div>
<button class="btn btn-danger remove-group-item-btn" data-bind="click: $parent.removeSelectedGroupItem" type="button">Remove</button>
</div>
</div>
</li>
</ul>
</div>
<span data-bind="text: allGroupItems().map(a => a.item())"></span>
Note:
You need to change the input binding inside foreach from $data to item (observable property name)
To check if a group item is already added, use some like this: self.allGroupItems().some(a => a.item() === self.groupItemToAdd())
The last span demonstrates that the observable is updated
I have a search that works with ajax. If the user clicks on one of the seach results, he gets on a new page. Now, if he klicks back on the browser UI, he gets back to the search. However, the value from the input is not getting saved and the search is empty. I would like to have keep the value.
The search is programmed in vue.js:
<template>
<div>
<div class="row">
<div class="col-12">
<div class="card no-shadow-card mb-2">
<div class="card-header primary-color white-text">
<div class="d-flex justify-content-between">
<span>Filter</span>
<div>
<a href="javascript:void(0)" class="card-toggle-body-visibility white-text"><i
class="fa fa-chevron-up rotated-icon" aria-hidden="true"></i></a>
</div>
</div>
</div>
<div class="card-body">
<div class="form-row mb-4">
<div class="col-md-6 mb-1">
<!-- First name -->
<input type="text" id="vacancieName" data-reset="filter"
class="form-control" placeholder="Name der Stellenanzeige" v-model="name">
</div>
</div>
<div class="form-row">
<div class="col-md-6">
<select class="md-form mdb-select"
name=""
searchable="Suchen"
v-model="company">
<option value="">Unternehmen</option>
<option v-for="ownCompany in ownCompanies" :value="ownCompany.id" v-text="ownCompany.title"></option>
</select>
<button type="button" class="btn-save btn btn-primary btn-sm">Ok</button>
</div>
<div class="col-md-6">
<select class="md-form mdb-select"
name=""
searchable="Suchen"
v-model="job">
<option value="" disabled>Beruf Auswählen</option>
<option v-for="avalibleJob in avalibleJobs" :value="avalibleJob.id" v-text="avalibleJob.name"></option>
</select>
<button type="button" class="btn-save btn btn-primary btn-sm">Ok</button>
</div>
</div>
<div class="col-12 float-right">
<button #click.prevent="getVacancies" type="button" class="btn btn-sm btn-light-blue">
Suchen
</button>
<button #click="resetFilter" type="button" class="btn btn-sm btn-unique">
Zurücksetzen
</button>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<vacancie-index-result-componment v-for="vacancie in vacancies" v-bind:vacancie="vacancie"
:key="vacancie.id"></vacancie-index-result-componment>
</div>
</div>
</template>
<script>
import VacancieIndexResultComponentComapany from './VacancieIndexResultComponentCompany.vue'
export default {
name: 'VacancieIndexComponentCompany',
components: {
'vacancie-index-result-componment': VacancieIndexResultComponentComapany,
},
data() {
return {
avalibleJobs: [],
ownCompanies: [],
vacancies: [],
name: '',
company: '',
job: ''
}
},
methods: {}//Some Axios methods to get the results
}
</script>
There are two ways to resolve your problems
Use dialog to handle your new page,above the
<body></body>or your root element ,it coast less code to resolve. it’s will hold the code
in a single component
Hard way or the best way whatever you say, is to use the vue-route system, use <keep-alive></keep-alive> tags to cache your components,
and you’ll see the value is still there.you can also see it in
dev-tools anyway.
I have an array in my data object and it will push as many time user wants to add data to it, and it is rendering with v-for perfectly.
The problem is related UI part didn't update, see the following picture :
this is init of the page and there is an empty object in array
when I press add button panel-body would not update with new v-for generated elements:
thanks
EDIT:
When I write the code in pure pure html(copy it in code), it look like this, that is a target UI.
EDIT 2:
data :
data() {
return {
payment: {
type: "check",
checks: [{}]
}
}
}
ui :
<div v-for="(check,index) in payment.checks">
<br>
<h5>
index of array ->
{{index}}
</h5>
<div class="form-group">
<label class="col-md-3 control-label">
something
<label style="color:red">*</label>
</label>
<div class="col-md-9">
<input type="text" class="form-control" v-model="check.amount" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">
someting else
<label style="color:red">*</label>
</label>
<div class="col-md-9">
<input type="text" class="form-control" v-model="check.dadada" />
</div>
</div>
<div class="col-lg-8" style="padding-top: 3%;">
<button v-on:click="payment.checks.push({})" class="btn btn-success" style="margin-right: 7%;">
add
</button>
</div>
</div>
I am wondering which way of calling mutiple components is better. Here we have example one which calls components in a composition type way another word for this would be (High-order functions???)
var App = React.createClass({
render:function () {
return(
<div>
<div className="container">
{this.props.children}
</div>
</div>
)
}
});
// Title Component
var Title = React.createClass({
render:function () {
return(
<App>
<div className="text-center">
<h1>Rock App</h1>
<h4>An Easy Way To Track Your Rock Climbing Progress</h4>
</div>
{this.props.children}
</App>
)
}
});
// Login Component
var Login = React.createClass({
render:function () {
return(
<Title>
<div>
<form className="form-horizontal">
<div className="form-group">
<label className="col-sm-2 control-label">Email</label>
<div className="col-sm-10">
<input type="email" className="form-control" id="inputEmail3" placeholder="Email"/>
</div>
</div>
<div className="form-group">
<label className="col-sm-2 control-label">Password</label>
<div className="col-sm-10">
<input type="password" className="form-control" id="inputPassword3" placeholder="Password"/>
</div>
</div>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button type="submit" className="btn btn-default">Sign in</button>
</div>
</div>
</form>
</div>
</Title>
)
}
});
ReactDOM.render(<Login/>, document.getElementById('app'));
Here you would call Login, which is within Title which is within App.
Another way is to create each component separately and have a main parent component which calls each sub-component children attributes like so...
var Title = React.createClass({
render: function () {
return(
<div className="head text-center">
<h1>Rock App</h1>
<h3>The only app you need to track your climbs</h3>
</div>
)
}
});
var Login = React.createClass({
render: function () {
return(
<div>
<form className="form-horizontal">
<div className="form-group">
<label className="col-sm-2 control-label">Email</label>
<div className="col-sm-10">
<input type="email" className="form-control" id="inputEmail3" placeholder="Email"/>
</div>
</div>
<div className="form-group">
<label className="col-sm-2 control-label">Password</label>
<div className="col-sm-10">
<input type="password" className="form-control" id="inputPassword3" placeholder="Password"/>
</div>
</div>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button type="submit" className="btn btn-default">Sign in</button>
</div>
</div>
</form>
</div>
)
}
});
var Homepage = React.createClass({
render: function () {
return(
<div>
<div className="container">
<Title>{this.props.children}</Title>
<Login>{this.props.children}</Login>
</div>
</div>
)
}
});
ReactDOM.render(<Homepage/>, document.getElementById('app'));
In my opinion the second way is much cleaner and is not dependent on other components. But I am just figuring out what way is standard.
this is straight from the React documentation:
When designing interfaces, break down the common design elements
(buttons, form fields, layout components, etc.) into reusable
components with well-defined interfaces. That way, the next time you
need to build some UI, you can write much less code. This means faster
development time, fewer bugs, and fewer bytes down the wire.
The beauty of React is being able to structure your application into simple, reusable components and have the option to pass data from the parent to the child components. So by having all your components in one file it's basically defeating the main objective of React.
I personally like to have an index file that handles my middleware and routes, and then a parent file for each section that handles imports and passing data down.