We are creating an application in vue
Does anyone know how to format text partially
like this?
You cannot create hard constraints from ellipses, but this functional may be procedural.
If you know what words you need to style, try like following snippet:
new Vue({
el: "#demo",
data() {
return {
messages: { unstyled: 'no styling!', styled: 'platformy dobrix del!' },
};
},
methods: {
words(string) {
return string.split(/\s+/);
},
isMarked(string) {
return /dobrix/i.test(string);
},
},
})
.marked {
color: red;
position:relative;
}
.marked::before {
content: "";
background: turquoise;
position: absolute;
height: 20px;
width: 92%;
top: 20px;
z-index: -1;
border-radius: 10px;
}
*{
font-weight: 800;
font-size: 32px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div class="container">
<div v-for="(value, name) in messages" :key="name">
<span v-for="(word, index) in words(value)" :key="index">
<span v-if="isMarked(word)" class="marked">{{ word }} </span>
<span v-else>{{ word }} </span>
</span>
</div>
</div>
</div>
I'm using VueJS and have nested elements which are dynamically created like so:
<container>
<outerElement class="outer" v-for="obj in objects">
<innerElement class="inner" v-for="element in obj"/>
</outerElement>
</container>
Now when it comes to CSS I'm having a slight problem. Since the innerElements are intended to be moveable, they need the outer element to have the same size/position as the container.
Is there some way in CSS to remove the box-model from the 'outer' class whilst remaining in the container?
Here's a sketch of what I'm trying to achieve.
EDIT:
To fix the mentioned XY-Problem, here is the template in a simplified version, using the same implementation methods as in my application.
<template>
<div class="home">
<h1>This is the main Page.</h1>
<h2>Testing area:</h2>
<br />Simple Data Example:
<br />
<div class="container">
<button #click="simpleXOR()">XOR</button>
{{ data }}
<vue-draggable-resizable
class="simple"
v-for="(bit,index) in simpleData"
:key="index"
:w="50"
:h="50"
:parent="true"
:resizable="false"
>
{{`Bit-${index} => `}}
<status-indicator :status="bit ? 'positive' : 'negative'" />
</vue-draggable-resizable>
</div>
<br />Nested Data Example
<div class="container">
<div class="outer" v-for="obj in nestedObj.data" :key="obj.name">
<div class="label">
<button #click="nestedXOR(obj.name)">XOR -> {{ obj.name }}</button>
{{ obj.states }}
</div>
<vue-draggable-resizable
class="inner"
v-for="(state, index) in obj.states"
:key="index"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div v-if="obj.contentType === 'TypeA'">
<b>{{ `Bit-${index} of ${obj.name}` }}</b>
<br />
<status-indicator :status="state ? 'positive' : 'negative'" />
</div>
<div v-else>
<b>{{ `Bit-${index} of ${obj.name}` }}</b>
<br />
<status-indicator :status="state ? 'active' : 'intermediary'" />
</div>
</vue-draggable-resizable>
</div>
</div>
</div>
</template>
<script>
// # is an alias to /src
export default {
name: "home",
components: {},
data() {
return {
simpleData: [0, 1, 0, 1],
nestedObj: {
data: [
{
states: [0, 1, 0, 1],
name: "a",
contentType: "TypeA"
},
{
states: [0, 1, 0, 1],
name: "b",
contentType: "TypeB"
}
]
}
};
},
computed: {
data() {
return this.simpleData;
}
},
methods: {
simpleXOR() {
var x = [];
for (var i = 0; i < this.simpleData.length; i++) {
x.push(this.simpleData[i] ^ 1);
}
this.simpleData = x;
console.debug(this.simpleData);
},
nestedXOR(name) {
var index = this.nestedObj.data.findIndex(obj => {
return obj.name === name;
});
var x = [];
for (var i = 0; i < this.nestedObj.data[index].states.length; i++) {
x.push(this.nestedObj.data[index].states[i] ^ 1);
}
this.nestedObj.data[index].states = x;
}
}
};
</script>
<style scoped>
.container {
margin: auto;
height: 200px;
width: 1000px;
border: 2px solid black;
position: relative;
}
.simple {
top: 0px;
left: 0px;
}
.outer {
display: contents; /* as suggested */
}
.inner {
/* ??? */
}
.label {
border: 1px dashed green;
padding: 10px;
height: 20%;
width: 20%;
}
/* // This is the css for vue-draggable-resizable */
/* // DON'T EDIT unless customization is needed */
.vdr {
touch-action: none;
position: absolute;
box-sizing: border-box;
border: 1px dashed black;
}
.handle {
box-sizing: border-box;
position: absolute;
width: 10px;
height: 10px;
background: #eee;
border: 1px solid #333;
}
.handle-tl {
top: -10px;
left: -10px;
cursor: nw-resize;
}
.handle-tm {
top: -10px;
left: 50%;
margin-left: -5px;
cursor: n-resize;
}
.handle-tr {
top: -10px;
right: -10px;
cursor: ne-resize;
}
.handle-ml {
top: 50%;
margin-top: -5px;
left: -10px;
cursor: w-resize;
}
.handle-mr {
top: 50%;
margin-top: -5px;
right: -10px;
cursor: e-resize;
}
.handle-bl {
bottom: -10px;
left: -10px;
cursor: sw-resize;
}
.handle-bm {
bottom: -10px;
left: 50%;
margin-left: -5px;
cursor: s-resize;
}
.handle-br {
bottom: -10px;
right: -10px;
cursor: se-resize;
}
#media only screen and (max-width: 768px) {
[class*="handle-"]:before {
content: "";
left: -10px;
right: -10px;
bottom: -10px;
top: -10px;
position: absolute;
}
}
</style>
Currently the problem in this code is that the innerElements can't be moved inside the container, because the outerElement is their container.
Since I can't change the parent selector to use the container instead of the outerElement this is hard to change.
Thus I wanted to make the outerElements borders non-existant so that the innerElement uses the container as parent.
But I suppose my thought is a bit weird, considering that the vue-draggable-resizable component will use the outerElement as parent anyways.
Here's a screenshot of the problem:
The moveable boxes can't be moved inside the container because the outerElement doesn't inherit the position and size of the container.
Try using CSS display:contents on the outer element. This display property basically makes the element "invisible" to the browser.
However, I think you'd be better off by refactoring your Vue template to remove the outer element. For example, you could process the objects array to combine its children before doing the loop.
For your simple example, you could just flatten the nested array before iterating over it:
<container>
<innerElement class="inner" v-for="element in objects.flat(1)" />
</container>
The more complex example you posted is a bit trickier, since the inner loop also needs access to obj. Still, you could do it by writing a custom method that wraps each state in an wrapper that contains both the state and a reference to the object it belongs to, like this:
<div class="container">
<div class="label" v-for="obj in nestedObj.data" :key="obj.name">
<button #click="nestedXOR(obj.name)">XOR -> {{ obj.name }}</button>
{{ obj.states }}
</div>
<vue-draggable-resizable
class="inner"
v-for="wrapper in flattenStates(nestedObj.data)"
:key="wrapper.key"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div v-if="wrapper.obj.contentType === 'TypeA'">
<b>{{ `Bit-${wrapper.index} of ${wrapper.obj.name}` }}</b>
<br />
<status-indicator :status="wrapper.state ? 'positive' : 'negative'" />
</div>
<div v-else>
<b>{{ `Bit-${wrapper.index} of ${wrapper.obj.name}` }}</b>
<br />
<status-indicator :status="wrapper.state ? 'active' : 'intermediary'" />
</div>
</vue-draggable-resizable>
</div>
where the flattenStates method would look something like this:
flattenStates: function (objects) {
return objects.flatMap( obj => {
return obj.states.map( (state, index) => {
return {
obj: obj,
state: state,
index: index,
key: obj.name + " state " + index
};
} );
} );
}
Compatibility note: .flat() and .flatMap() are not available on IE or on current stable versions of Edge. To make this code work on those browsers, you'll need a polyfill. The new Chromium-based versions of Edge, still in beta as of this writing, do however support both.
Alternatively, you could simplify the template by moving some logic into the flattenStates method:
<div class="container">
<!-- label divs omitted for brevity -->
<vue-draggable-resizable
class="inner"
v-for="wrapper in flattenStates(nestedObj.data)"
:key="wrapper.title"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div>
<b>{{ wrapper.title }}</b>
<br />
<status-indicator :status="wrapper.status" />
</div>
</vue-draggable-resizable>
</div>
flattenStates: function (objects) {
return objects.flatMap( obj => {
return obj.states.map( (state, index) => {
const wrapper = {
title: `Bit-${index} of ${obj.name}` // also used as :key
};
if (obj.contentType === 'TypeA') {
wrapper.status = (state ? 'positive' : 'negative');
} else {
wrapper.status = (state ? 'active' : 'intermediary');
}
return wrapper;
} );
} );
}
...or even:
<div class="container">
<!-- label divs omitted for brevity -->
<vue-draggable-resizable
class="inner"
v-for="(status, title) in flattenStates(nestedObj.data)"
:key="title"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div>
<b>{{ title }}</b>
<br />
<status-indicator :status="status" />
</div>
</vue-draggable-resizable>
</div>
flattenStates: function (objects) {
const objStates = {};
for (const obj of objects) {
obj.states.forEach( (state, index) => {
const title = `Bit-${index} of ${obj.name}`;
if (obj.contentType === 'TypeA') {
objStates[title] = (state ? 'positive' : 'negative');
} else {
objStates[title] = (state ? 'active' : 'intermediary');
}
} );
}
return objStates;
}
Learning React.js framework and need some pointers on styling. CSS isn't my forte.
How do I style the static content div in the middle and make it scrollable only within the div?
No styling:
https://i.imgur.com/26wNAfH.jpg
How to style this?
https://i.imgur.com/c5nYCOz.jpg
Here's the scroll function:
https://storage.googleapis.com/hatchways-app.appspot.com/assessments/data/frontend/part%202.mp4
app.css
.name {
font-weight: bold;
font-size: 20px;
}
.centered {
margin: auto;
width: 50%;
border: 3px solid green;
padding: 10px;
}
.center {
position: fixed;
width: 500px;
height: 200px;
top: 50%;
left: 50%;
margin-top: -100px; /* Negative half of height. */
margin-left: -250px; /* Negative half of width. */
}
.content {
text-align: center;
border: 2px solid grey;
border-radius: 5px;
position: fixed;
/* center the div */
right: 0;
left: 0;
margin-right: auto;
margin-left: auto;
/* give it dimensions */
min-height: 10em;
width: 90%;
/* just for example presentation */
top: 5em;
background-color: white;
}
Output: https://i.imgur.com/Eyv6hab.png
HTML:
import React, { Component } from "react";
import "../App.css";
import "../../node_modules/bootstrap/dist/css/bootstrap.min.css";
const API = "https://www.hatchways.io/api/assessment/students";
class App extends Component {
constructor(props) {
super(props);
this.state = {
students: [],
isLoading: false,
error: null
};
}
componentDidMount() {
this.setState({ isLoading: true });
fetch(API)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error("Something went wrong ...");
}
})
.then(data =>
this.setState({ students: data.students, isLoading: false })
)
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
const { students, isLoading, error } = this.state;
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<body>
<div className="content">
<div>
{students.map(student => (
<div key={student.id}>
<p>
<img src={student.pic} />
</p>
<p className="name">
{student.firstName} {student.lastName}
</p>
<p>Email: {student.email}</p>
<p>Company: {student.company}</p>
<p> Skill: {student.skill}</p>
<p>Average: {student.grades}</p>
</div>
))}
</div>
</div>
{/* <div class="card mb-3">
{students.map(student => (
<div class="row no-gutters">
<div class="col-md-4">
<img src={student.pic} class="card-img" alt="..." />
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">
{student.firstName} {student.lastName}
</h5>
<p class="card-text">
<p>Email: {student.email}</p>
<p>Company: {student.company}</p>
<p> Skill: {student.skill}</p>
<p>Average: {student.grades}</p>
</p>
</div>
</div>
</div>
))}
</div> */}
</body>
);
}
}
export default App;
This might not help I am unfamiliar with that JS framework. I am only posting this because nobody has answered and maybe this can help.
<style>
scroll
{
max-height: 400px;
overflow-y: scroll;
}
</style>
<div class="scroll">
I'm trying to change the code from showing a placeholder "quantity" to having a default value of 1. Users have given feedback that it would help to have a common value in place, instead of having to enter it.
Here's what I tried, it removes the placeholder, but the number field looks blank. (when I inspect element, it does show my code, just the number does not appear in the box.) I'm not very experienced in input coding, any help is appreciated. Thanks!
<div class="bo-quantity-input-section bo-col-3">
<input type="number" value="1"
ng-model="lineItem.quantity"
ng-change="quantityChanged()"
tabindex="[[1000 + 2 * index + 1]]"/>
</div>
Here's the original chunk of code:
<div class="bo-quantity-input-section bo-col-3">
<input type="number" placeholder="Quantity"
ng-model="lineItem.quantity"
ng-change="quantityChanged()"
tabindex="[[1000 + 2 * index + 1]]"/>
</div>
Here's the entire page:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/angucomplete-alt/1.3.0/angucomplete-alt.min.js"></script>
<div ng-app="bulkOrderAppModule">
<div ng-controller="BulkOrderRootCtrl" class="bo-app"><bo-line-item ng-repeat="lineItem in lineItems" line-item="lineItem" index="$index" all-line-items="lineItems"> </bo-line-item>
<div class="bo-row">
<div class="bo-add-line-item bo-col-12"><a ng-click="addLineItem()"> Add Line Item </a></div>
</div>
<div class="bo-row">
<div class="bo-cart-controls">
<div class="bo-cart-link bo-col-6"> Go to Cart - Total: <span ng-bind-html="cart['total_price'] | shopifyMoneyFormat"></span> | [[cart['item_count'] ]] Items </div>
<div class="bo-clear-cart bo-col-3"><a ng-click="clearCart()"> Clear Cart </a></div>
<div class="bo-update-cart bo-col-3"><button class="btn bo-update-cart-btn" ng-disabled="!hasChanges" ng-click="updateCart()"> Update Cart </button></div>
</div>
</div>
</div>
<script type="text/ng-template" id="line-item-template">// <![CDATA[
<div class="bo-line-item">
<div class="bo-row">
<div class="bo-variant-input-section bo-col-8">
<angucomplete-alt ng-if="!lineItem.searchResult"
placeholder="Search for products by name or SKU"
pause="400"
selected-object="selectResult"
remote-url="/search?type=product&view=bulk-order-json&q="
remote-url-data-field="results"
title-field="product_title,variant_title"
image-field="thumbnail_url"
input-class="bo-variant-input"
bo-configure-angucomplete bo-tabindex="[[1000 + 2 * index]]">
</angucomplete-alt>
<div ng-if="lineItem.searchResult">
<div class="bo-col-2 bo-img-container">
<img class="bo-img" ng-src="[[lineItem.searchResult['thumbnail_url'] ]]"/>
</div>
<div class="bo-col-10">
<div class="bo-line-item-details">
[[lineItem.searchResult['product_title'] ]]
<span ng-if="lineItem.searchResult['variant_title']">
-
[[lineItem.searchResult['variant_title'] ]]
</span>
<span ng-if="lineItem.searchResult['sku']">
-
[[lineItem.searchResult['sku'] ]]
</span>
</div>
<div class="bo-line-item-price" ng-if="lineItem.searchResult['price']">
Unit price: <span ng-bind-html="lineItem.searchResult['price'] | shopifyMoneyFormat"></span>
</div>
<div ng-if="numVariants() > 1 && !lineItem.expanded">
<a href="javascript:void(0)" ng-click="expandAllVariants()">
Expand all [[numVariants()]] variants
</a>
</div>
</div>
</div>
</div>
<div class="bo-quantity-input-section bo-col-3">
<input type="number" placeholder="Quantity"
ng-model="lineItem.quantity"
ng-change="quantityChanged()"
tabindex="[[1000 + 2 * index + 1]]"/>
</div>
<div class="bo-remove-section bo-col-1">
<a href="javascript:void(0)" ng-click="deleteLineItem()">
<div class="bo-svg-container">
<svg viewBox="0 0 49 49" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M24.486,-3.55271368e-15 C10.984,-3.55271368e-15 -3.55271368e-15,10.985 -3.55271368e-15,24.486 C-3.55271368e-15,37.988 10.984,48.972 24.486,48.972 C37.988,48.972 48.972,37.988 48.972,24.486 C48.972,10.984 37.988,-3.55271368e-15 24.486,-3.55271368e-15 L24.486,-3.55271368e-15 Z M24.486,45.972 C12.638,45.972 3,36.331 3,24.485 C3,12.637 12.639,3 24.486,3 C36.334,3 45.972,12.638 45.972,24.486 C45.972,36.334 36.334,45.972 24.486,45.972 L24.486,45.972 Z M32.007,16.965 C31.42,16.379 30.471,16.379 29.885,16.965 L24.486,22.365 L19.087,16.966 C18.501,16.38 17.552,16.38 16.966,16.966 C16.381,17.551 16.38,18.502 16.966,19.088 L22.365,24.486 L16.965,29.886 C16.38,30.471 16.379,31.421 16.965,32.007 C17.55,32.593 18.501,32.592 19.086,32.007 L24.486,26.607 L29.884,32.006 C30.47,32.591 31.42,32.591 32.005,32.006 C32.592,31.419 32.591,30.47 32.005,29.884 L26.607,24.486 L32.007,19.087 C32.593,18.501 32.592,17.551 32.007,16.965 L32.007,16.965 Z" id="Shape" fill="#404040" sketch:type="MSShapeGroup"></path>
</g>
</svg>
</div>
</a>
</div>
</div>
<div class="bo-row" ng-if="showLineItemAlreadyExistsMsg">
<div class="bo-col-12 bo-line-item-already-exists-msg">
A line item already exists for that product
</div>
</div>
</div>
// ]]></script><script>// <![CDATA[
var template = document.getElementById('line-item-template');
template.innerHTML = template.innerHTML.replace('// <![CDATA[', '').replace('// ]]>', '');
// ]]></script></div>
<style><!--
.bo-app {
padding: 20px 0px 10px 0px;
border: 1px solid #EEEEEE;
}
.bo-variant-input-section {
display: inline-block;
}
.bo-quantity-input-section {
display: inline-block;
}
.bo-remove-section {
display: inline-block;
height: 50px;
line-height: 50px;
text-align: center;
}
.bo-svg-container {
padding: 5px 0px;
}
.bo-remove-section svg {
height: 25px;
width: 25px;
}
.bo-variant-input {
width: 100%;
}
.bo-line-item {
margin-bottom: 20px;
}
.bo-line-item input {
height: 50px !important;
width: 100% !important;
padding-top: 0px !important;
padding-bottom: 0px !important;
}
.bo-img {
margin-left: 0px !important;
max-height: 50px !important;
width: auto !important;
}
.bo-img-container {
max-height: 50px !important;
}
.bo-line-item-details {
font-size: 1.05rem;
}
.angucomplete-searching {
padding: 0px 5px;
font-size: 1.05rem;
}
.angucomplete-holder{
position: relative;
}
.angucomplete-dropdown {
margin-top: 0px;
padding: 20px 10px;
background-color: #FCFCFC;
border: 1px solid #DDDDDD;
max-height: 360px;
overflow: scroll;
position: absolute;
z-index: 999;
width: 100%;
}
.angucomplete-row {
min-height: 50px;
margin-bottom: 20px;
cursor: pointer;
}
.angucomplete-image-holder {
width: calc(16.66666667% - 20px);
float: left;
padding: 0px 5px;
margin: 0px !important;
}
.angucomplete-image {
max-height: 50px !important;
width: auto !important;
}
.angucomplete-title {
width: calc(83.33333333% - 20px);
float: left;
font-size: 1.05rem;
padding: 0px 5px;
}
.bo-add-line-item {
position: relative;
font-size: 1.05rem;
margin-top: 10px;
}
.bo-cart-controls {
margin-top: 20px;
font-size: 1.05rem;
}
.bo-clear-cart,
.bo-update-cart {
text-align: right;
margin-bottom: 10px;
}
.bo-update-cart-btn {
float: right;
max-width: 80%;
position: relative;
bottom: 5px;
}
.bo-line-item-already-exists-msg {
color: red;
}
.bo-row {
padding: 0px 10px;
min-height: 50px;
}
.bo-col-1 {
width: calc(8.33333333% - 20px);
float: left;
}
.bo-col-2 {
width: calc(16.6666667% - 20px);
float: left;
}
.bo-col-3 {
width: calc(25% - 20px);
float: left;
}
.bo-col-4 {
width: calc(33.33333333% - 20px);
float: left;
}
.bo-col-5 {
width: calc(41.66666667% - 20px);
float: left;
}
.bo-col-6 {
width: calc(50% - 20px);
float: left;
}
.bo-col-7 {
width: calc(58.33333333% - 20px);
float: left;
}
.bo-col-8 {
width: calc(66.66666667% - 20px);
float: left;
}
.bo-col-9 {
width: calc(75% - 20px);
float: left;
}
.bo-col-10 {
width: calc(83.33333333% - 20px);
float: left;
}
.bo-col-11 {
width: calc(91.66666667% - 20px);
float: left;
}
.bo-col-12 {
width: calc(100% - 20px);
float: left;
}
.bo-col-1, .bo-col-2, .bo-col-3, .bo-col-4, .bo-col-5, .bo-col-6,
.bo-col-7, .bo-col-8, .bo-col-9, .bo-col-10, .bo-col-11, .bo-col-12 {
margin: 0px 10px;
}
--></style><script>// <![CDATA[
(function() {
function BulkOrderRootCtrl($scope, $http, $timeout) {
$scope.lineItems = [];
$scope.cart = null;
$scope.hasChanges = false;
$http.get('/cart.js').success(function(response) {
$scope.cart = response;
});
$scope.addLineItem = function(opt_initial) {
$scope.lineItems.push({
searchResult: null,
expanded: false,
quantity: null
});
if (!opt_initial) {
$scope.hasChanges = true;
}
};
// Initialize the first empty line item in a timeout.
// Certain themes look for number inputs at page load time
// and replace them with custom widgets.
$timeout(function() {
$scope.addLineItem(true);
});
$scope.updateCart = function() {
$http.post('/cart/update.js', {
'updates': _.reduce($scope.lineItems, function(obj, lineItem) {
if (lineItem.searchResult && _.isNumber(lineItem.quantity)) {
obj[lineItem.searchResult['variant_id']] = lineItem.quantity;
}
return obj;
}, {})
})
.success(function(response) {
$scope.cart = response;
$scope.hasChanges = false;
$scope.lineItems = _.filter($scope.lineItems, function(lineItem) {
return lineItem.quantity > 0;
});
})
.error(function(response) {
// Handle out of stock here
console.log(response);
});
};
$scope.clearCart = function() {
$http.post('/cart/clear.js')
.success(function(response) {
$scope.cart = response;
$scope.lineItems = [];
$scope.hasChanges = false;
});
};
$scope.$on('quantity-changed', function() {
$scope.hasChanges = true;
});
$scope.$on('delete-line-item', function(event, lineItem) {
var idx = $scope.lineItems.indexOf(lineItem);
if (idx != -1) {
$scope.lineItems.splice(idx, 1);
}
});
$scope.$on('expand-all-variants', function(event, lineItem) {
var idx = $scope.lineItems.indexOf(lineItem);
if (idx != -1) {
var args = [idx, 1];
angular.forEach(lineItem.searchResult['product']['variants'], function(variant) {
var imageUrl = '';
if (variant['featured_image'] && variant['featured_image']['src']) {
imageUrl = variant['featured_image']['src']
} else if (lineItem.searchResult['product']['featured_image']) {
imageUrl = lineItem.searchResult['product']['featured_image'];
}
args.push({
quantity: lineItem.searchResult['variant_id'] == variant['id'] ? lineItem.quantity : null,
expanded: true,
searchResult: {
'product_title': lineItem.searchResult['product_title'],
'variant_title': variant['title'],
'variant_id': variant['id'],
'sku': variant['sku'],
'price': variant['price'],
'url': variant['url'],
'product': lineItem.searchResult['product'],
'thumbnail_url': shopifyImageUrl(imageUrl, 'thumb')
}
});
});
Array.prototype.splice.apply($scope.lineItems, args);
}
});
}
function boLineItem() {
return {
scope: {
lineItem: '=',
index: '=',
allLineItems: '='
},
templateUrl: 'line-item-template',
controller: function($scope) {
$scope.showLineItemAlreadyExistsMsg = false;
$scope.selectResult = function(result) {
$scope.showLineItemAlreadyExistsMsg = false;
if ($scope.variantLineItemAlreadyExists(result.originalObject['variant_id'])) {
$scope.showLineItemAlreadyExistsMsg = true;
} else {
$scope.lineItem.searchResult = result.originalObject;
}
};
$scope.variantLineItemAlreadyExists = function(variantId) {
var exists = false;
angular.forEach($scope.allLineItems, function(lineItem) {
if (lineItem !== $scope.lineItem && lineItem.searchResult['variant_id'] == variantId) {
exists = true;
}
});
return exists;
};
$scope.quantityChanged = function() {
$scope.$emit('quantity-changed');
};
$scope.deleteLineItem = function() {
if (_.isNumber($scope.lineItem.quantity)) {
$scope.lineItem.quantity = 0;
$scope.quantityChanged();
} else {
$scope.$emit('delete-line-item', $scope.lineItem);
}
};
$scope.numVariants = function() {
return $scope.lineItem.searchResult['product']['variants'].length;
};
$scope.expandAllVariants = function() {
$scope.$emit('expand-all-variants', $scope.lineItem);
};
}
};
}
function boConfigureAngucomplete($timeout) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var input = element.find('input');
input.attr('tabindex', attrs.boTabindex);
$timeout(function() {
input.focus();
});
}
};
}
function shopifyImageUrl(url, imageType) {
if (url.indexOf('_' + imageType + '.') != -1) {
return url;
}
var dotIdx = url.lastIndexOf('.');
return [url.slice(0, dotIdx), '_', imageType, url.slice(dotIdx, url.length)].join('');
}
function shopifyMoneyFormat($shopifyMoneyFormatString, $sce) {
return function(cents) {
return $sce.trustAsHtml(Shopify.formatMoney(cents, $shopifyMoneyFormatString));
};
}
function interpolator($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}
// Polyfill for themes that don't include these:
function polyfillShopifyBuiltins() {
if (!window['Shopify']) {
window['Shopify'] = {};
}
if (!Shopify.formatMoney) {
Shopify.formatMoney = function(cents, format) {
if (typeof cents == 'string') cents = cents.replace('.','');
var value = '';
var patt = /\{\{\s*(\w+)\s*\}\}/;
var formatString = (format || this.money_format);
function addCommas(moneyString) {
return moneyString.replace(/(\d+)(\d{3}[\.,]?)/,'$1,$2');
}
switch(formatString.match(patt)[1]) {
case 'amount':
value = addCommas(floatToString(cents/100.0, 2));
break;
case 'amount_no_decimals':
value = addCommas(floatToString(cents/100.0, 0));
break;
case 'amount_with_comma_separator':
value = floatToString(cents/100.0, 2).replace(/\./, ',');
break;
case 'amount_no_decimals_with_comma_separator':
value = addCommas(floatToString(cents/100.0, 0)).replace(/\./, ',');
break;
}
return formatString.replace(patt, value);
};
if (!window['floatToString']) {
window['floatToString'] = function(numeric, decimals) {
var amount = numeric.toFixed(decimals).toString();
if(amount.match(/^\.\d+/)) {return "0"+amount; }
else { return amount; }
}
}
}
}
polyfillShopifyBuiltins();
angular.module('bulkOrderAppModule', ['angucomplete-alt'], interpolator)
.controller('BulkOrderRootCtrl', BulkOrderRootCtrl)
.directive('boLineItem', boLineItem)
.directive('boConfigureAngucomplete', boConfigureAngucomplete)
.filter('shopifyMoneyFormat', shopifyMoneyFormat)
.value('$shopifyMoneyFormatString', BO_MONEY_FORMAT);
})();
// ]]></script>
I have created a custom directive, it's a spinner. it's working out side the ng-repeat and it's not working inside the ng-repeat.
Here is my html
<body ng-controller="controller">
<div>
<div>Spinner</div>
<div spinner jump="jump"> </div>
Spinner Value:- <span>{{jump}}</span>
<div>inside ng-repeat</div>
<div ng-repeat="i in counter(4) track by $index" >{{$index+1}}_spinner{{$index.i}}
<spinner result="jump" ng-model="jump"></spinner>
</div>
</div>
JS
var app = angular.module('plunker', [])
.directive('spinner', function() {
return {
restrict: 'EA',
scope: {
result:'=jump'
},
link: function ($scope, $element, $attrs) {
$scope.result = 0;
$scope.spinning = function(action) {
if(($scope.txtbox === '' || $scope.txtbox === undefined) && action === "add"){
$scope.result= Number($scope.result) +1;
}
else if(($scope.txtbox === '' || $scope.txtbox === undefined) && action === "sub") {
$scope.result= Number($scope.result) - 1;
}
else if($scope.txtbox !== '' && action === "sub") {
$scope.result = Number($scope.result) - Number($scope.txtbox);
}
else{
$scope.result = Number($scope.txtbox) + Number($scope.result);
}
};
},
templateUrl: 'spinnerDirective.html',
};
})
.controller('controller', ['$scope', function($scope) {
$scope.counter = Array;
}]);
Directive
<body>
<div class="container">
<div> Jumps: <input type='text' id="jumps" ng-model='txtbox'/></div>
<div style="float: left; width:120px; margin-top:10px;" >
<div style="border-color: red; border-style: solid; border-width: 1px 1px 1px 1px; margin-left: 10px; text-align: center; height: 30px; line-height: 2px;" >
<label style="vertical-align: top;line-height: normal;" ng-click="spinning('add');" >+</label>
</div>
<div style="margin-top: -12px; text-align: center; height:12px;margin-left: 7px;">
<label id="spinn" style="background-color: #fff;font-size:18px;" >{{result}}</label>
</div>
<div style="border-color: red; border-style: solid; border-width: 0 1px 1px 1px; margin-left: 10px; text-align: center; height: 30px;line-height: 27px;">
<label style="vertical-align: bottom;line-height: normal;" ng-click="spinning('sub');">-</label>
</div>
</div>
</div>
</body>
http://plnkr.co/edit/KPHqes1baju70oSYRdRp?p=preview
I need my inside ng-repeat spinner should work same as the outside ng-repeat spinner and have to display the value of each spinner separately.