Leff7

Experience

18,540

0 Best Reply Awards

  • Member Since 2 Years Ago
  • 92 Lessons Completed
  • 0 Favorites

30th August, 2018

Leff7 started a new conversation Creating Mock Api In React Project Using Redux And Duck File Structure • 3 weeks ago

I am quite new in redux world and have not yet had a project structured with ducks. I am trying to understand it and use it to make a mock api, since I don't have the backend ready yet. I am working with the legacy code, that I am trying to figure out. There is a folder called data, that has a duck and a backendApi file. Duck file looks like this.

data/duck.jsx

import { createSelector } from 'reselect';
import { createReduxApi } from './backendApi';

const getDataContext = state => state.default.dataContext;

const backendReduxApi = createBackendReduxApi(getDataContext);

// Action creators
export const makeRestApiRequest = endpointName => backendReduxApi .makeRequestActionCreator(endpointName);

export const resetRestApi = endpointName => backendReduxApi .makeResetActionCreator(endpointName);

// Reducers
export const dataReducer = backendReduxApi .createReducer();

// Selectors
const getRestApiState = endpointName => backendReduxApi .getEndpointState(endpointName);
export const getRestApiData = endpointName => createSelector([getRestApiState(endpointName)], apiState => apiState.data);
export const getRestApiMeta = endpointName => createSelector([getRestApiState(endpointName)], apiState => apiState.meta);
export const getRestApiError = endpointName => createSelector([getRestApiState(endpointName)], apiState => apiState.error);
export const getRestApiStarted = endpointName => createSelector([getRestApiState(endpointName)], apiState => apiState.started);
export const getRestApiFinished = endpointName => createSelector([getRestApiState(endpointName)], apiState => apiState.finished);

The backendApi.jsx file looks like this:

data/backendApi.jsx

import ReduxRestApi from './rest/ReduxRestApi';

export const BackendApi = { // NOSONAR
  LANGUAGE_FILE: 'languageFile',
  EMPLOYEE: 'employee',
};

const backendReduxApiBuilder = ReduxRestApi.build()
  /* /api */

  /* /api/employee */
  .withGet('/myproject/api/employee', BackendApi.NAV_ANSATT)

  /* /language*/
  .withGet('/myproject/language/nb_NO.json', BackendApi.LANGUAGE_FILE)

export const createBackendReduxApi = restApiSelector => backendReduxApiBuilder
  .withRestApiSelector(restApiSelector)
  .create();

Then in the data/rest folder I have 4 files: ReduxRestApi, restConfig, RestDuck and restMethods.

data/rest/ReduxRestApi.jsx

import { combineReducers } from 'redux';
import { get, post, postAndOpenBlob } from './restMethods';
import RestDuck from './RestDuck';

class ReduxRestApi {
  constructor(endpoints, getRestApiState) {
    this.createReducer = this.createReducer.bind(this);
    this.getEndpoint = this.getEndpoint.bind(this);
    this.makeRequestActionCreator = this.makeRequestActionCreator.bind(this);
    this.makeResetActionCreator = this.makeResetActionCreator.bind(this);
    this.getEndpointState = this.getEndpointState.bind(this);
    this.ducks = endpoints.map(({ name, path, restMethod }) => new RestDuck(name, path, restMethod, getRestApiState));
  }

  createReducer() {
    const reducers = this.ducks
      .map(duck => ({ [duck.name]: duck.reducer }))
      .reduce((a, b) => ({ ...a, ...b }), {});
    return combineReducers(reducers);
  }

  getEndpoint(endpointName) {
    return this.ducks.find(duck => duck.name === endpointName)
      || { actionCreators: {} };
  }

  makeRequestActionCreator(endpointName) {
    return this.getEndpoint(endpointName).actionCreators.execRequest;
  }

  makeResetActionCreator(endpointName) {
    return this.getEndpoint(endpointName).actionCreators.reset;
  }

  getEndpointState(endpointName) {
    return this.getEndpoint(endpointName).stateSelector;
  }

  static build() {
    class RestApiBuilder {
      constructor() {
        this.withGet = this.withGet.bind(this);
        this.withPost = this.withPost.bind(this);
        this.withPostAndOpenBlob = this.withPostAndOpenBlob.bind(this);
        this.withRestApiSelector = this.withRestApiSelector.bind(this);
        this.endpoints = [];
      }

      withGet(path, name) {
        this.endpoints.push({ path, name, restMethod: get });
        return this;
      }

      withPost(path, name) {
        this.endpoints.push({ path, name, restMethod: post });
        return this;
      }

      withPostAndOpenBlob(path, name) {
        this.endpoints.push({ path, name, restMethod: postAndOpenBlob });
        return this;
      }

      withRestApiSelector(restApiSelector) {
        this.restApiSelector = restApiSelector;
        return this;
      }

      create() {
        return new ReduxRestApi(
          this.endpoints,
          this.restApiSelector
        );
      }
    }

    return new RestApiBuilder();
  }
}

export default ReduxRestApi;

restConfig.jsx

import axios from 'axios';
import { removeErrorMessage, showErrorMessage } from '../../app/duck';
import { is401Error, isHandledError } from '../../app/ErrorTypes';

const isDevelopment = process.env.NODE_ENV === 'development';

const configureRequestInterceptors = (store) => {
  const onRequestAccepted = (config) => {
    store.dispatch(removeErrorMessage());
    return config;
  };

  const onRequestRejected = error => Promise.reject(error);

  axios.interceptors.request.use(onRequestAccepted, onRequestRejected);
};

const configureResponseInterceptors = (store) => {
  const onSuccessResponse = response => response;

  const onErrorResponse = (error) => {
    if (is401Error(error) && !isDevelopment) {
      window.location.reload();
    }
    if (!isHandledError(error)) {
      store.dispatch(showErrorMessage(error));
    }
    return Promise.reject(error);
  };

  axios.interceptors.response.use(onSuccessResponse, onErrorResponse);
};

const configureRestInterceptors = (store) => {
  configureRequestInterceptors(store);
  configureResponseInterceptors(store);
};

export default configureRestInterceptors;

data/rest/RestDuck.jsx

import { createSelector } from 'reselect';

import { get, getBlob, post, postAndOpenBlob, postBlob } from './restMethods';

/**
 * getMethodName
 * Helper function that maps given AJAX-method to a name
 *
 * Ex. getMethodName(getBlob) -> 'GET'
 */
const getMethodName = (restMethod) => {
  switch (restMethod) {
    case get:
    case getBlob:
      return 'GET';
    case post:
    case postBlob:
    case postAndOpenBlob:
      return 'POST';
    default:
      return '';
  }
};

/**
 * createRequestActionType
 * Helper function to generate actionType for actions related to AJAX calls
 *
 * Ex: createRequestActionType('fetchEmployee', 'ERROR', get, '/myproject/api/employee') -> '@@REST/fetchEmployee GET /myproject/api/employeeERROR'
 */
const createRequestActionType = (name, qualifier, restMethod = '', path = '') => [`@@REST/${name}`, getMethodName(restMethod), path, qualifier]
  .filter(s => s !== '')
  .join(' ');

/**
 * createRequestActionTypes
 * Helper function to generate ActionTypes for a given AJAX method and resource.
 *
 * Ex. createRequestActionType(fetchEmployee, get, '/myproject/api/employee') -> {
 *   reset: '@@REST GET /myproject/api/employee RESET',
 *   requestStarted: '@@REST GET /myproject/api/employee STARTED',
 *   requestError: '@@REST GET /myproject/api/employee ERROR',
 *   requestFinished: '@@REST GET /myproject/api/employee FINISHED',
 * }
 */
const createRequestActionTypes = (name, restMethod, path) => ({
  reset: createRequestActionType(name, 'RESET'),
  requestStarted: createRequestActionType(name, 'STARTED', restMethod, path),
  requestError: createRequestActionType(name, 'ERROR', restMethod, path),
  requestFinished: createRequestActionType(name, 'FINISHED', restMethod, path)
});

/**
 * createRequestThunk
 * Helper function that generates a thunk that performs an AJAX call specified by 'restMethod' and 'restEndpoint'
 *
 * When the thunk is running, the action 'requestStarted' will be dispatched immediately.
 * Then, it performs the AJAX call that returns a promise.
 *  If the call goes well, the action 'requestFinished' will be dispatched with data from the call.
 * If the call fails, the action 'requestError' is dispatched with the contents of the error.
 */
const createRequestThunk = (restMethod, restEndpoint, requestStarted, requestFinished, requestError) => (
  (params, options = {}) => (dispatch) => {
    dispatch(requestStarted(params, options));
    return restMethod(restEndpoint, params)
      .catch((error) => {
        const data = error.response && error.response.data ? error.response.data : error;
        dispatch(requestError(data));
        return Promise.reject(error);
      })
      .then((response) => {
        dispatch(requestFinished(response.data));
        return response;
      });
  }
);

/**
 * createRequestActionCreators
 * Helper function that creates action creators 'requestStarted', 'requestFinished' and 'requestError',
 * @see createRequestThunkCreator
 */
const createRequestActionCreators = (restMethod, restEndpoint, actionTypes) => {
  const reset = () => ({ type: actionTypes.reset });
  const requestStarted = (params, options = {}) => ({ type: actionTypes.requestStarted, payload: { params, timestamp: Date.now() }, meta: { options } });
  const requestFinished = data => ({ type: actionTypes.requestFinished, payload: data });
  const requestError = error => ({ type: actionTypes.requestError, payload: error });
  const execRequest = createRequestThunk(restMethod, restEndpoint, requestStarted, requestFinished, requestError);
  return {
    reset, requestStarted, requestFinished, requestError, execRequest
  };
};

/**
 * createRequestReducer
 *
 * Helper function that creates a reducer for an AJAX call.
 * Reducer alters the state of the actions with the name defined by
 *   actionTypes.requestStarted
 *   actionTypes.requestFinished
 *   actionTypes.requestError
 */
const createRequestReducer = (restMethod, resourceName, actionTypes) => {
  const initialState = {
    data: undefined,
    meta: undefined,
    error: undefined,
    started: false,
    finished: false
  };

  return (state = initialState, action = {}) => {
    switch (action.type) {
      case actionTypes.requestStarted:
        return {
          ...initialState,
          data: action.meta.options.keepData ? state.data : initialState.data,
          started: true,
          meta: action.payload
        };
      case actionTypes.requestFinished:
        return {
          ...state,
          started: false,
          finished: true,
          data: action.payload
        };
      case actionTypes.requestError:
        return {
          ...state,
          started: false,
          error: action.payload
        };
      case actionTypes.reset:
        return {
          ...initialState
        };
      default:
        return state;
    }
  };
};

/**
 * RestDuck
 * Class that offers action types, action creators, reducers and selectors for an AJAX call.
 * @see createRequestActionTypes
 * @see createRequestActionCreators
 * @see createRequestReducer
 *
 * Ex.
 * const getEmployeeDuck = new RestDuck(execGetRequest, 'employee', GET_EMPLOYEE_SERVER_URL);
 * // Action creators
 * export const fetchEmployee = getEmployeeDuck.actionCreators.execRequest;
 * // Reducer
 * export const dataReducer = combineReducers(
 *   ...,
 *   getEmployeeDuck.reducer,
 * }
 * // Selectors
 * export const getDataContext = state => state.default.dataContext;
 * export const getEmployeeData = getEmployeeDuck.selectors.getRequestData(getDataContext);
 * export const getEmployeeStarted = getEmployeeDuck.selectors.getRequestStarted(getDataContext);
 * ...
 */
class RestDuck {
  constructor(name, path, restMethod, getApiContext) {
    this.restMethod = restMethod;
    this.name = name;
    this.path = path;
    this.getApiContext = getApiContext;
    this.$$duck = {}; // for class internal use
  }

  get actionTypes() {
    if (!this.$$duck.actionTypes) {
      this.$$duck.actionTypes = createRequestActionTypes(this.name, this.restMethod, this.path);
    }
    return this.$$duck.actionTypes;
  }

  get actionCreators() {
    if (!this.$$duck.actionCreators) {
      this.$$duck.actionCreators = createRequestActionCreators(this.restMethod, this.path, this.actionTypes);
    }
    return this.$$duck.actionCreators;
  }

  get reducer() {
    if (!this.$$duck.reducer) {
      this.$$duck.reducer = createRequestReducer(this.restMethod, this.name, this.actionTypes);
    }
    return this.$$duck.reducer;
  }

  get stateSelector() {
    return createSelector([this.getApiContext], restApiContext => restApiContext[this.name]);
  }
}

export default RestDuck;

data/rest/restMethods.jsx

import axios, { CancelToken } from 'axios';

const openPreview = (data) => {
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(data);
  } else {
    window.open(URL.createObjectURL(data));
  }
};

const cancellable = (config) => {
  let cancel;
  const request = axios({
    ...config,
    cancelToken: new CancelToken((c) => { cancel = c; })
  });
  request.cancel = cancel;
  return request.catch(error => (axios.isCancel(error) ? Promise.reject(new Error(null)) : Promise.reject(error)));
};

const defaultHeaders = {
  'Cache-Control': 'no-cache',
  Pragma: 'no-cache',
  Expires: 0
};

const defaultPostHeaders = {
  'Content-Type': 'application/json'
};

export const get = (url, params, responseType = 'json') => cancellable({
  url,
  params,
  responseType,
  method: 'get',
  headers: {
    ...defaultHeaders
  }
});

export const post = (url, data, responseType = 'json') => cancellable({
  url,
  responseType,
  data: JSON.stringify(data),
  method: 'post',
  headers: {
    ...defaultHeaders,
    ...defaultPostHeaders
  },
  cache: false
});

export const getBlob = (url, params) => get(url, params, 'blob');

export const postBlob = (url, data) => post(url, data, 'blob');

export const postAndOpenBlob = (url, data) => postBlob(url, data)
  .then((response) => {
    openPreview(response.data);
    return {
      ...response,
      data: 'blob opened as preview' // Don't waste memory by storing blob in state
    };
  });

I am not sure where to place and how to do mock api calls in this structure. I was thinking of making a mock api similiar to this one, where I would mimick the ajax calls and store them in the redux, but just not sure how to do this in this kind of setup?

8th March, 2018

Leff7 started a new conversation CSS Flexbox- Making A Div Take It's Content Height Not Working • 6 months ago

I would like to set the width of the div, and it's content by the width of one of the paragraphs in it. This is the html structure:

<div class="panel">
    <p class="user-title"></p>
    <div></div>
</div>

Currently I have the styling set up like this for the .panel:

.panel {
    width: 20rem;
    display: flex;
    flex-direction: column;
    flex: 0 1 270px;
}

.user-title {
    margin: 0;
    font-size: 0.875rem;
    line-height: 1.25rem;
    font-family: 'Source Sans Pro', Arial, sans-serif;
    font-weight: 400;
}

The problem I have is that the text inside the paragraph tags with the class .user-title, breaks to another line in Chrome, and Edge, and not in IE. I would like to keep the text in the same line, and that everything else takes the width of that text.

I have tried with setting the .panel to:

width: auto;
height: auto;
display: inline-flex;
flex-direction: column;
flex: 0 1 auto;
position: relative;

And the child div to:

position: absolute;
width: 100%;
top: 30px;

Then, the .panel and the child div, take the width of the paragraph inside of it. But, the child element goes out of the bounderis of the panel element in it's height, the panel is not covering the height of both the paragraph and the child div.

How can I fix that?

4th March, 2018

Leff7 started a new conversation Algolia Autocomplete Dropdown Menu Not Visible On Small Screens • 6 months ago

I am using [algolia autocomplete][1] in my app. I have a layout with a header bar that has a search input for bigger screens. On small screens I only have a magnifying glass icon, that on click toggles another header with a search bar, that I initially have it hidden. This is the layout:

<header class="mdc-toolbar mdc-toolbar--fixed toolbar--custom">
  <div class="mdc-toolbar__row">
    <section class="menu mdc-toolbar__section mdc-toolbar__section--align-start">
      <a href="#" class="material-icons mdc-toolbar__menu-icon">menu</a>
      <span class="mdc-toolbar__title">Title</span>
    </section>
    <section class="mdc-toolbar__section">
      <form action="/search" method="get" class="search-field-desktop">
        <div class="mdc-text-field mdc-text-field--box mdc-text-field--with-leading-icon autocomplete-search-field">
          <i class="material-icons mdc-text-field__icon" tabindex="0">search</i>
          <input name="q"
                 type="text"
                 class="mdc-text-field__input search-input-js aa-input-search"
                 placeholder="Search for players and videos ..."
                 aria-label="Full-Width Text Field">
        </div>
      </form>
    </section>
    <section class="mdc-toolbar__section mdc-toolbar__section--align-end" role="toolbar">
      <a href="#" id="search-input-open" class="material-icons mdc-toolbar__icon" aria-label="Search" alt="Search">search</a>
      <a href="#" class="material-icons mdc-toolbar__icon" aria-label="Login" alt="Login">more_vert</a>
    </section>
  </div>
</header>
<header class="search-field-phone mdc-toolbar mdc-toolbar--fixed toolbar--custom">
  <div class="mdc-toolbar__row">
    <a id="search-input-close" class="material-icons mdc-toolbar__menu-icon" tabindex="0">arrow_back</a>
    <form action="/search" method="get">
      <div class="mdc-text-field mdc-text-field--box autocomplete-search-field">
        <input name="q"
                type="text"
                class="mdc-text-field__input search-input-js aa-input-search"
                placeholder="Search for players and videos ..."
                aria-label="Full-Width Text Field"
                autofocus>
      </div>
    </form>
  </div>
</header>

The problem I have is that the dropdown menu is not visible on small screens for some reason and on bigger screens it is. This is the scss/css:

.algolia-autocomplete {
  display: flex!important;
  flex: auto!important;
  height: 100%;
}
.aa-dropdown-menu {
  position: relative;
  top: -6px;
  border-radius: 3px;
  margin: 6px 0 0;
  padding: 0;
  text-align: left;
  height: auto;
  position: relative;
  background: $white;
  border: 1px solid #ccc;
  width: 100%;
  left: 0 !important;
  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2), 0 2px 3px 0 rgba(0, 0, 0, 0.1);
}

.aa-dropdown-menu .aa-suggestions {
  position: relative;
  z-index: 1000;
}

.aa-dropdown-menu [class^="aa-dataset-"] {
  position: relative;
  border: 0;
  border-radius: 3px;
  overflow: auto;
  padding: 0;
  color: #3c3e42;
  font-weight: 500;
}

.aa-dropdown-menu * {
  box-sizing: border-box;
}

.aa-suggestion {
  display: block;
  width: 100%;
  height: 72px;
  clear: both;

  .mdc-list-item {
    height: 72px;
  }
}
.aa-suggestion span {
  white-space: nowrap !important;
  text-overflow: ellipsis;
  overflow: hidden;
  display: block;
  float: left;
  line-height: 1em;
  width: calc(100% - 30px);
}
.aa-suggestion.aa-cursor {
  background-color: transparent;
}
.aa-suggestion em {
  color: #00bcd4;
  font-weight: 700;
}
.aa-suggestion img {
  float: left;
  height: 44px;
  width: 44px;
  margin-right: 6px;
}

.aa-suggestion a {
  color: #3c3e42;
}

.aa-suggestions-category {
  font-weight: 700;
  color: #3c3e42;
  border-bottom: 1px solid rgba(102, 105, 105, 0.17);
}

.powered-by-algolia {
  padding-left: 15px;
  border-top: 1px solid rgba(102, 105, 105, 0.17);
  display: flex;
  align-items: center;
  height: 30px;
}

.aa-input-container {
  display: inline-block;
  position: relative; }
.aa-input-search {
  width: 100%;
  height: 30px;
  padding: 12px 28px 12px 12px;
  box-sizing: border-box;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none; }
.aa-input-search::-webkit-search-decoration, 
.aa-input-search::-webkit-search-cancel-button, 
.aa-input-search::-webkit-search-results-button, 
.aa-input-search::-webkit-search-results-decoration {
  display: none;
}
.media {
  margin: 10px 0;
}
.media-body {
  p {
    margin: 0;
  }
}
.toolbar--custom {
  color: $white;

  .mdc-toolbar__row {
    min-height: 56px;
  }

  form, .autocomplete-search-field {
    width: 100%;
  }

  .mdc-text-field--box:not(.mdc-text-field--upgraded) {
    height: 36px;
  }
  .mdc-text-field--box {
    overflow: visible;
    margin: auto;

    .mdc-text-field__icon {
      bottom: 8px;
      font-size: 22px;
    }
  }

  .mdc-text-field--box:after,
  .mdc-text-field--box:before {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }

  #search-input-open {
    display: none;
  }

  @media only screen and (max-width: 782px) {
    #search-input-open {
      display: block;
    }
    .search-field-desktop {
      display: none;
    }
  }
}

.search-field-phone {
  clip-path: circle(0%);
  visibility: hidden;
  .mdc-text-field {
    clip-path: circle(0%);
  }
}

@mixin search-animated-open {
  -webkit-animation: open 0.3s forwards;
  animation: open 0.3s forwards;
  animation-timing-function: $mdc-animation-standard-curve-timing-function;
}

@mixin search-animated-close {
  -webkit-animation: close 0.3s forwards;
  animation: close 0.3s forwards;
  animation-timing-function: $mdc-animation-standard-curve-timing-function;
}

.search-field-phone-open,  {
  visibility: visible;
  @include search-animated-open;

  .mdc-text-field {
    @include search-animated-open;
  }
}

.search-field-phone-close,  {
  @include search-animated-close;

  .mdc-text-field {
    @include search-animated-close;
  }
}

@keyframes open {
  from {
    clip-path: circle(0 at calc(100% - 68px) 50%);
  }
  to {
    clip-path: circle(150% at calc(100% - 68px) 50%);
  }
}
@keyframes close {
  from {
    clip-path: circle(150% at calc(100% - 68px) 50%);
  }
  to {
    clip-path: circle(0 at calc(100% - 68px) 50%);
    visibility: hidden;
  }
}

The layout of the whole page looks like this:

<div id="app">
    @include('layouts.partials.sidebar')
    @include('layouts.partials.navigation')
    <div class="page-content">
        @yield('content')
    </div>
</div>

Where the navigation partial is the file with headers shown above. This is the sidebar partial:

<aside class="mdc-drawer mdc-drawer--temporary mdc-typography">
  <nav class="mdc-drawer__drawer">
    <header class="mdc-drawer__header">
      <div class="mdc-drawer__header-content">
        Header here
      </div>
    </header>
    <nav id="icon-with-text-demo" class="mdc-drawer__content mdc-list">
      <a class="mdc-list-item mdc-list-item--activated" href="#">
        <i class="material-icons mdc-list-item__graphic" aria-hidden="true">inbox</i>Inbox
      </a>
      <a class="mdc-list-item" href="#">
        <i class="material-icons mdc-list-item__graphic" aria-hidden="true">star</i>Star
      </a>
    </nav>
  </nav>
</aside>

This is the css for the page:

body {
  margin: 0;
}
#app {
  display: flex;
}
.page-content {
  display: inline-flex;
  flex-direction: column;
  flex-grow: 1;
  height: 100%;
  box-sizing: border-box;
}

I am not sure what is causing this behaviour, why is the dropdown menu for bigger screens visible, and the one for smaller screens not? [1]: https://www.algolia.com/doc/tutorials/search-ui/autocomplete/auto-complete/?language=javascript#custom-ranking

17th February, 2018

Leff7 started a new conversation Algolia Autocomplete Js Menu - Getting Error On Creating The List Of Elements • 7 months ago

I am trying to use material web components to style the dropdown menu of the algolia autocomplete js. I have made a template that looks like this:

templates: {
        header: '<div class="mdc-list-group">',
        footer: `<div class="powered-by-algolia">
                   <div class="pull-right"><img src="/imagecache/xs/Algolia_logo_bg-white.jpg" /></div>
                 </div>
              </div>`
      }
    },
    [{
      source: autocomplete.sources.hits(players, { hitsPerPage: 5 }),
      displayKey: 'first_name',
      debug: true,
      templates: {
        header: `<h3 class="mdc-list-group__subheader">Players</h3>
                 <ul class="mdc-list mdc-list--two-line">`,
        suggestion: (suggestion) => {
          return `<span>
                   <a href="/player/${ suggestion.id }/${ suggestion.first_name.toLowerCase() + '-' + suggestion.last_name.toLowerCase() }">
                     <div class="media">
                       <div class="media-left">
                         <img class="media-object" src="/imagecache/small/${ suggestion.image_filename }">
                       </div>
                       <div class="media-body">
                         <p>${suggestion._highlightResult.first_name.value + ' ' + suggestion._highlightResult.last_name.value }<small> ${old} years</small></p>
                         <small>${suggestion.nationality + ' '+ (suggestion.position ? suggestion.position : '')}</small>
                       </div>
                     </div>
                   </a>
                  </span>`;
        },
        footer: '</ul>',
      }
    },
    {
      source: autocomplete.sources.hits(videos, { hitsPerPage: 5 }),
      displayKey: 'title',
      debug: true,
      templates: {
        header: '<div class="aa-suggestions-category"><span>Videos</span></div>',
        suggestion: (suggestion) => {
          timeAgo();
          return `<span>
                   <a href="/player/video/${suggestion.uid}/${suggestion.player_name.toLowerCase() + '-' + suggestion.player_surname.toLowerCase()}">
                    <div class="media">
                      <img class="d-flex mr-3" src="https://s3.eu-central-1.amazonaws.com/videos.football-talents.com/${suggestion.video_id}_1.jpg">
                      <div class="media-body">
                        <p>${suggestion._highlightResult.title.value}<small class="timeago" title="${suggestion.created_at}">${suggestion.created_at}</small></p>
                        <small>${suggestion._highlightResult.player_name.value + ' ' + suggestion._highlightResult.player_surname.value}</small>
                      </div>
                    </div>
                  </a>
                </span>`;
        },
        footer: '<div>This is videos footer</div>',
      }
    }

But, I get an error:

Uncaught DOMException: Failed to execute 'querySelectorAll' on 'Document': '</ul>' is not a valid selector.

Why can't I close the ul element in the footer? How can I fix this?

31st January, 2018

Leff7 started a new conversation CSS - Animation With Clip Path Circle • 7 months ago

I am using material web components and I would like to make a search field that opens on click with animation, that would have the effect shown on this page at small screen sizes. I have made a toolbar with the search icon that I show on small screens and that on clicking reveals the search input field that takes the whole width of the toolbar.

Html:

<header class="mdc-toolbar mdc-toolbar--fixed toolbar-light">
  <div class="mdc-toolbar__row">
    <section class="menu mdc-toolbar__section mdc-toolbar__section--align-start">
      <a href="#" class="material-icons mdc-toolbar__menu-icon">menu</a>
      <span class="mdc-toolbar__title">Title</span>
    </section>
    <section class="mdc-toolbar__section">
      <form action="/search" method="get">
        <div class="mdc-text-field mdc-text-field--box mdc-text-field--with-leading-icon autocomplete-search-field">
          <i class="material-icons mdc-text-field__icon" tabindex="0">search</i>
          <input name="q"
                 type="text"
                 class="mdc-text-field__input search-input-js aa-input-search"
                 placeholder="Search for players and videos ..."
                 aria-label="Full-Width Text Field">
        </div>
      </form>
    </section>
    <section class="mdc-toolbar__section mdc-toolbar__section--align-end" role="toolbar">
      <a href="#" id="search-input-icon" class="material-icons mdc-toolbar__icon" aria-label="Download" alt="Download">search</a>
      <a href="#" class="material-icons mdc-toolbar__icon" aria-label="Auth" alt="Auth">more_vert</a>
    </section>
  </div>
</header>

<!-- hidden initially, shown on clicking the search icon -->
<header class="search-field-phone mdc-toolbar mdc-toolbar--fixed toolbar-light">
  <div class="mdc-toolbar__row">
    <form action="/search" method="get">
      <div class="mdc-text-field mdc-text-field--box mdc-text-field--with-leading-icon autocomplete-search-field">
        <i class="material-icons mdc-text-field__icon" tabindex="0">arrow_back</i>
        <input name="q"
                type="text"
                class="mdc-text-field__input search-input-js aa-input-search"
                placeholder="Search for players and videos ..."
                aria-label="Full-Width Text Field"
                autofocus>
      </div>
    </form>
  </div>
</header>

CSS:

#search-input-icon {
    display: none;
}

@media only screen and (max-width: 782px) {
    #search-input-icon {
      display: block;
    }
}

.search-field-phone {
  visibility: hidden;
}

With js, I just change the classes and visibility of the search field. I am removing the class search-field-phone the heade, that has this property:

  clip-path: circle(0%);
  visibility: hidden;

And adding the class search-field-phone-open that sets the visibility to visible and has the animation:

@keyframes open {
from {
    clip-path: circle(0 at calc(100% - 20%) 50%);
  }
  to {
    clip-path: circle(150% at calc(100% - 20%) 50%);
  }
}

And on clicking the close button I am changing the class to search-field-phone-close that has the animation:

@keyframes close {
  from {
    clip-path: circle(150% at calc(100% - 20%) 50%);
  }
  to {
    clip-path: circle(0 at calc(100% - 20%) 50%);
    visibility: hidden;
  }
}

JS:

let openIcon = document.querySelector('#search-input-open');
let closeIcon = document.querySelector('#search-input-close');
let inputField = document.querySelector('.search-field-phone');
openIcon.addEventListener('click', () => {
    inputField.classList.add('search-field-phone-open');
    inputField.classList.remove('search-field-phone-close', 'search-field-phone');
});
closeIcon.addEventListener('click', () => {
    inputField.classList.add('search-field-phone-close');
    inputField.classList.remove('search-field-phone-open');
});

And this is the css:

.search-field-phone {
  clip-path: circle(0%);
  visibility: hidden;
  .mdc-text-field {
    clip-path: circle(0%);
  }
}

@mixin search-animated-open {
  -webkit-animation: open 2s forwards;
  animation: open 2s forwards;
}

@mixin search-animated-close {
  -webkit-animation: close 2s forwards;
  animation: close 2s forwards;
}

.search-field-phone-open,  {
  visibility: visible;
  overflow: hidden;
  @include search-animated-open;

  .mdc-text-field {
    @include search-animated-open;
  }
}

.search-field-phone-close,  {
  overflow: hidden;
  @include search-animated-close;

  .mdc-text-field {
    @include search-animated-close;
  }
}

@keyframes open {
  from {
    clip-path: circle(0 at calc(100% - 20%) 50%);
  }
  to {
    clip-path: circle(150% at calc(100% - 20%) 50%);
  }
}
@keyframes close {
  from {
    clip-path: circle(150% at calc(100% - 20%) 50%);
  }
  to {
    clip-path: circle(0 at calc(100% - 20%) 50%);
    visibility: hidden;
  }
}

But, I am not sure how can I make it close and open as a proper circle from and to the search icon? This is what I get now:

enter image description here

27th January, 2018

Leff7 started a new conversation Vagrant Not Working - Timeout While Waiting For The Machine To Boot • 7 months ago

I have installed the latest versions of Virtualbox v.5.2.6 and Vagrant v.2.0.1 on the windows machine with the Intel-Core-i5-4210U-Processor @1.70Ghz 2.40Ghz. I have added the homestead box by running the command:

 vagrant box add laravel/homestead

But, on running the vagrant up it runs fine until this point:

Timed out while waiting for the machine to boot. This means that Vagrant was unable to communicate with the guest machine within the configured ("config.vm.boot_timeout" value) time period.

If you look above, you should be able to see the error(s) that Vagrant had when attempting to connect to the machine. These errors are usually good hints as to what may be wrong.

If you're using a custom box, make sure that networking is properly working and you're able to connect to the machine. It is a common problem that networking isn't setup properly in these boxes. Verify that authentication configurations are also setup properly, as well.

If the box appears to be booting properly, you may want to increase the timeout ("config.vm.boot_timeout") value.

I have looked around I tried out different things but couldn't find any solution. On running the vagrant ssh-config I get:

Host homestead-7
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile C:/Users/MyUser/.vagrant.d/insecure_private_key
IdentitiesOnly yes
LogLevel FATAL
ForwardAgent yes

How can I get this working?

22nd January, 2018

Leff7 started a new conversation CSS - Material Web Components Implementing Drawer With The Hero Section • 7 months ago

I am have started working with material web components on a new project for the first time. I am trying to use their persistent drawer with the hero section on a page, where I also have a toolbar. The template looks like this:

<div id="app">
  <aside class="mdc-drawer mdc-drawer--persistent mdc-typography">
    <nav class="mdc-drawer__drawer">
      <header class="mdc-drawer__header">
        <div class="mdc-drawer__header-content">
          Header here
        </div>
      </header>
      <nav id="icon-with-text-demo" class="mdc-drawer__content mdc-list">
        <a class="mdc-list-item mdc-list-item--activated" href="#">
          <i class="material-icons mdc-list-item__graphic" aria-hidden="true">inbox</i>Inbox
        </a>
        <a class="mdc-list-item" href="#">
          <i class="material-icons mdc-list-item__graphic" aria-hidden="true">star</i>Star
        </a>
      </nav>
    </nav>
  </aside>
  <header class="mdc-toolbar mdc-toolbar--fixed demo-toolbar">
    <div class="mdc-toolbar__row">
      <section class="menu mdc-toolbar__section mdc-toolbar__section--align-start">
        <a href="#" class="material-icons mdc-toolbar__menu-icon">menu</a>
        <span class="mdc-toolbar__title">Title</span>
      </section>
      <section class="mdc-toolbar__section">
        Section aligns to center.
      </section>
      <section class="mdc-toolbar__section mdc-toolbar__section--align-end" role="toolbar">
        <a href="#" class="material-icons mdc-toolbar__icon" aria-label="Download" alt="Download">file_download</a>
        <a href="#" class="material-icons mdc-toolbar__icon" aria-label="Print this page" alt="Print this page">print</a>
        <a href="#" class="material-icons mdc-toolbar__icon" aria-label="Bookmark this page" alt="Bookmark this page">bookmark</a>
      </section>
    </div>
  </header>
  <div class="page-content">
     <div class="landing-page-hero">
     </div>
  </div>
</div>

I don't have much css, I have copied from their demo the css for the page-content and added css for the landing-page-hero:

body {
  margin:0;
}
.page-content {
  display: inline-flex;
  flex-direction: column;
  flex-grow: 1;
  height: 100%;
  box-sizing: border-box;
}
.landing-page-hero {
  min-height: 400px;
  height: 45vh;
  width: 100vw;
  background-image: url('/img/hero-image.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: 90% 60%;
  display: flex;
  align-items: center;
  color: $white;
}

But, this is not working the drawer is not visible on clicking the menu, and the hero is not immediately below the toolbar but there looks like their is margin-bottom from the drawer that pushes it further down. enter image description here

How can I make this work? So, that I have a toolbar with the drawer and a hero section immediately below the toolbar?

20th January, 2018

Leff7 left a reply on How To Configure Paths In Webpack To Material Web Components In A Laravel Project • 8 months ago

Thank you very much, that was it!

Leff7 left a reply on How To Configure Paths In Webpack To Material Web Components In A Laravel Project • 8 months ago

But still they will try to import with the path @material/<some component> and then it won't work. That is why I need to configure the path in webpack I think, but I don't know how is that done?

Leff7 left a reply on How To Configure Paths In Webpack To Material Web Components In A Laravel Project • 8 months ago

But, I am doing that already in my app.scss file with this:

@import '~material-components-web/material-components-web';

The problem is that material-components-web when I opened the package inside the node_modules, has index.js file that imports all the components:

@import "@material/button/mdc-button";
@import "@material/card/mdc-card";
@import "@material/checkbox/mdc-checkbox";
@import "@material/dialog/mdc-dialog";
@import "@material/drawer/mdc-drawer";
@import "@material/elevation/mdc-elevation";
@import "@material/fab/mdc-fab";
@import "@material/form-field/mdc-form-field";
@import "@material/grid-list/mdc-grid-list";
@import "@material/icon-toggle/mdc-icon-toggle";
@import "@material/layout-grid/mdc-layout-grid";
@import "@material/linear-progress/mdc-linear-progress";
@import "@material/list/mdc-list";
@import "@material/menu/mdc-menu";
@import "@material/radio/mdc-radio";
@import "@material/ripple/mdc-ripple";
@import "@material/select/mdc-select";
@import "@material/slider/mdc-slider";
@import "@material/snackbar/mdc-snackbar";
@import "@material/switch/mdc-switch";
@import "@material/tabs/mdc-tabs";
@import "@material/textfield/mdc-text-field";
@import "@material/theme/mdc-theme";
@import "@material/toolbar/mdc-toolbar";
@import "@material/typography/mdc-typography";

So, there it can' t find all this individual components, and also since I wouldn't like to change the files inside the node_modules folder, I am wondering how can I then setup the webpack, so that this files are loaded properly?

Leff7 started a new conversation How To Configure Paths In Webpack To Material Web Components In A Laravel Project • 8 months ago

I would like to use [material web components][1] in my Laravel project. I have installed the components by running the command:

npm install --save material-components-web

But, when I have run the npm run dev command I got an error that modules where not found.I am wondering why all the components where not installed just by running that command? So I installed each module individually, by running the command:

npm install --save @material/< component name >

I have included the package in my app.js and app.scss files like this:

App.js

window.mdc = require('material-components-web/dist/material-components-web')
window.mdc.autoInit();

App.scss

@import '~material-components-web/material-components-web';

And then I got an error, when running the npm run dev command:

ERROR in ./resources/assets/sass/app.scss
Module build failed: ModuleBuildError: Module build failed: 
@import "@material/button/mdc-button";

What do I need to do to configure importing of the modules for both js and scss part to work? In the docs it says:

NOTE: The components' Sass files expect that the node_modules directory containing the @material scope folder is present on the Sass include path.

How can I set this up in laraval's webpack.mix.js? [1]: https://github.com/material-components/material-components-web

19th January, 2018

Leff7 left a reply on Route Model Binding With Request Headers • 8 months ago

Yes, I know, I was just wondering if there is any solution to this, so that I don't need to repeat it in a lot of methods in various controllers?

Leff7 started a new conversation Route Model Binding With Request Headers • 8 months ago

I am wondering is it possible to do something similar to route model binding, but with request headers. I have a query that I check on my api endpoints, that looks like this:

User::where('telephone', $request->header('x-user'))->firstOrFail();

Is it possible to somehow avoid repeating this query in every method in controllers, but to apply it to routes?

Leff7 left a reply on How To Use Vue Material In A Project • 8 months ago

Oh, yes, of course, I haven't noticed they have properties, but when I move everything to vue component, the errors are gone, but the nav bar is not fixed.

Leff7 started a new conversation How To Use Vue Material In A Project • 8 months ago

I am trying to implement vue-material in my laravel v.5.5 project, I have installed the package, and I am importing the js part in my app.js and css file in my sass file like it says in the docs:

App.js

window.Vue = require('vue');

import VueMaterial from 'vue-material';
Vue.use(VueMaterial);

App.scss

@import '~vue-material/dist/vue-material.min.css';

I am trying to implement the vue-material app component in my blade view, like this:

@extends('layouts.app')

@section('content')
<div class="page-container">
  <md-app md-waterfall md-mode="fixed-last">
    <md-app-toolbar class="md-large md-dense md-primary">
      <div class="md-toolbar-row">
        <div class="md-toolbar-section-start">
          <md-button class="md-icon-button" @click="menuVisible = !menuVisible">
            <md-icon>menu</md-icon>
          </md-button>

          <span class="md-title">My Title</span>
        </div>

        <div class="md-toolbar-section-end">
          <md-button class="md-icon-button">
            <md-icon>more_vert</md-icon>
          </md-button>
        </div>
      </div>

      <div class="md-toolbar-row">
        <md-tabs class="md-primary">
          <md-tab id="tab-home" md-label="Home"></md-tab>
          <md-tab id="tab-pages" md-label="Pages"></md-tab>
          <md-tab id="tab-posts" md-label="Posts"></md-tab>
          <md-tab id="tab-favorites" md-label="Favorites"></md-tab>
        </md-tabs>
      </div>
    </md-app-toolbar>

    <md-app-drawer :md-active.sync="menuVisible">
      <md-toolbar class="md-transparent" md-elevation="0">Navigation</md-toolbar>

      <md-list>
        <md-list-item>
          <md-icon>move_to_inbox</md-icon>
          <span class="md-list-item-text">Inbox</span>
        </md-list-item>

        <md-list-item>
          <md-icon>send</md-icon>
          <span class="md-list-item-text">Sent Mail</span>
        </md-list-item>

        <md-list-item>
          <md-icon>delete</md-icon>
          <span class="md-list-item-text">Trash</span>
        </md-list-item>

        <md-list-item>
          <md-icon>error</md-icon>
          <span class="md-list-item-text">Spam</span>
        </md-list-item>
      </md-list>
    </md-app-drawer>

    <md-app-content>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error quibusdam, non molestias et! Earum magnam, similique, quo recusandae placeat dicta asperiores modi sint ea repudiandae maxime? Quae non explicabo, neque.</p>
    </md-app-content>
  </md-app>
</div>
@endsection

But, I get errors in the console:

[Vue warn]: Property or method "menuVisible" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

(found in )

How can I fix this?

18th January, 2018

Leff7 started a new conversation Laravel - How To Calculate The Sum Of Objects In An Array In Blade View • 8 months ago

I have a foreach loop in a blade view, where I am listing the objects that have a pivot property price:

                @foreach($transaction->options as $option)
                  <div class="row">
                    <div class="col-md-6">
                      <p>Option description: {{ $option->description }}</p>
                      <p>Price: {{ $option->pivot->price }}</p>
                    </div>
                  </div>
                  <hr>
                @endforeach
                <div class="row">
                  <div class="col-md-6">
                    <h4>Options total: </h4>
                  </div>
                </div>

I would like to since I am doing a foreach loop here, calculate the sum of all the options so that I could write it next to Options total:

I have tried with this:

               @foreach($transaction->options as $option)
                  <div class="row">
                    <div class="col-md-6">
                      <p>Option description: {{ $option->description }}</p>
                      <p>Price: {{ $option->pivot->price }}</p>
                      @php($total += $option->pivot->price)
                    </div>
                  </div>
                  <hr>
                @endforeach
                <div class="row">
                  <div class="col-md-6">
                    <h4>Options total: {{ $total }}</h4>
                  </div>
                </div>

But, that didn't work, I got an error:

Undefined variable: total

How can I do this?

Leff7 left a reply on Javascript/Vue.js - Filtering An Array Not Working • 8 months ago

Yes, that was the case I was missing the return, thanks in any case!

Leff7 started a new conversation Javascript/Vue.js - Filtering An Array Not Working • 8 months ago

I have a component, where I am passing an array with object as a property to it. Each object looks something like this:

{
  id: 1,
  flight_number: "dy234",
  from_date:"2018-01-17 12:15:01",
  to_date:"2019-03-17 09:22:25",
  user: {
    email:"[email protected]"
    id:1
    name:"Joe Doe"
    telephone:"4755555"
  },
  vehicle: {
    registration:"DN 1234"
  }
}

I also have an input that I would like to use a search filter for this array of objects. I have made a computed property where I am doing this:

filteredTransactions() {
   let filteredTransactions = this.transactions.filter(transaction => {
        transaction.flight_number.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.user.name.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.user.email.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.user.telephone.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.vehicle.registration.toLowerCase().includes(this.search.toLowerCase())
    })

    return filteredTransactions;
}

This is the whole component:

<template>
  <div>
    <div class="panel-heading">Transcations
      <input
        class="input pull-right"
        type="text"
        placeholder="Søk på bruker, flight num, eller bil..."
        v-model="search">
    </div>
    <div class="table-responsive">
      <table class="table table-hover">
        <thead>
            <tr>
                <th>Flight num.</th>
                <th>From</th>
                <th>To</th>
                <th>User</th>
                <th>Vehicle</th>
            </tr>
        </thead>
        <tbody>
          <tr v-for="(item, index) in filteredTransactions" :key="item.id">
            <th>{{ item.flight_number }}</th>
            <td>{{ dates[index].fromDate }}</td>
            <td>{{ dates[index].toDate }}</td>
            <td>
              <p>Name: {{ item.user.name }}</p>
              <p>Email: {{ item.user.email }}</p>
              <p>Phone: {{ item.user.telephone }}</p>
            </td>
            <td>{{ item.vehicle.registration }}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>
<script>
export default {
  props: ['items'],
  data () {
    return {
      transactions: [],
      search: '',
    }
  },
  created() {
    this.transactions = this.items;
  },
  methods: {
  },
  computed: {
    dates() {
      let dates = this.transactions.map(item => {
          return {
                   'fromDate': formatDate(item.from_date),
                   'toDate': formatDate(item.to_date)
                 }
      });

      function formatDate(date) {
        let formatedDate = new Date(date);
        const options = { year: 'numeric', month: 'long', day: 'numeric' };

        return formatedDate.toLocaleDateString('nb-NB', options);
      }

      return dates;
    },
    filteredTransactions() {
      let filteredTransactions = this.transactions.filter(transaction => {
        transaction.flight_number.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.user.name.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.user.email.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.user.telephone.toLowerCase().includes(this.search.toLowerCase()) ||
        transaction.vehicle.registration.toLowerCase().includes(this.search.toLowerCase())
      })

      return filteredTransactions;
    }
  }
}
</script>

But, the filteredTransactions array is empty, there are no errors in the console or vue debug tools, so not sure what is wrong here?

15th January, 2018

Leff7 left a reply on PHP/Laravel - How To Initiate A Class With It's Dependencies In A Trait • 8 months ago

I am asking how to use a class method in a trait SupplementaryFormatter not the other way around.

Leff7 started a new conversation PHP/Laravel - How To Initiate A Class With It's Dependencies In A Trait • 8 months ago

I would like to use a method from a class that I have in one trait. The class that I need looks like this:

namespace App\Http\Controllers;

use App\Libraries\Content\ContentInterface;
use Illuminate\Http\Request;
use App\Http\Requests;
use Corcel\Post;
use EllipseSynergie\ApiResponse\Laravel\Response;
use App\Transformers\IndexTransformer;

class ImportController extends Controller
{
    private $indexable;

    function __construct(Response $response, ContentInterface $contentInterface)
    {
        $this->indexable = \Config::get('middleton.wp.content.indexable_types');
        $this->response = $response;
        $this->contentInterface = $contentInterface;

    }

    public function updateOrCreateInventory($remoteId)
    {
       $this->contentInterface->updateOrCreateInventory($remoteId);
    }
}

I would like to use the updateOrCreateInventory method in a trait that I have or to be more specific in it's method :

namespace App\Libraries\Content;

use App\Inventory;
use GuzzleHttp\Client;

use App\Http\Controllers\ImportController;

trait SupplementaryFormatter
{

    private static function getInventoryUrl($id)
    {
        if (is_numeric($id)) {
           $inventory = Inventory::where('remote_id', $id)->first();

           if(!$inventory) {
              ImportController::updateOrCreateInventory($id);
           } else {
              return  '/' . $inventory->url;
           }
        }
        return $id;
     }
 }

But, I am not sure how can I initiate the class in the trait with it's dependencies, because when I import the Response and ContentInterface class to a trait and try to pass it to the constructor of the ImportController class, like so:

(new ImportController(new Response, new ImportController))->updateOrCreateInventory($id);

I get an error that I am not passing dependencies to Response and ImportController. How can I make this work?

11th January, 2018

Leff7 left a reply on Vue.js 2 - Persisting Property Value Without Vuex • 8 months ago

I am already using that, but the problem is when I am using browser back button, I get the cached site with the deleted items.

Leff7 started a new conversation Vue.js 2 - Persisting Property Value Without Vuex • 8 months ago

I have a small project where I use Laravel and Vue for some interactions, a simple non SPA app. I am passing an array of items from Laravel template to Vue component like this:

<extras :items="{{ json_encode($data) }}"></extras>

In Vue component I am listing all this items, and using another child component alert that I use for modal where a user can delete an item. This is the extras component:

<template>
  <div>
    <div v-for="item in extras" :key="item.id" class="media row">
      <div class="media-left col-sm-3">
        <a href="#">
          <img v-if="item.image_path != ''" class="media-object" :src="item.image_path" :alt="item.title">
        </a>
      </div>
      <div class="media-body col-sm-6">
        <h4 class="media-heading">{{ item.title }}</h4>
        <p>{{ item.description }}</p>
      </div>
      <div class="col-sm-3 action-buttons">
        <a class="btn btn-info" :href="`/extras/${item.id}/edit`" role="button">Rediger</a>
        <alert :id="item.id"></alert>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: ['items'],
  data () {
    return {
      extras: []
    }
  },
  created() {
      this.extras = this.items;
      this.$eventHub.$on('extras.delete',(id) => {
          this.extras = this.extras.filter(function(el) {
            return el.id !== id;
          });
      })
  }
}
</script>

And this is the alert component where I delete an item:

<template>
  <div>
    <a @click="openSimplert" class="btn btn-danger" role="button">Slett</a>
    <div :id="id" @click="closeSimplert" :class="`close-${id}`" class="modal">
      <div class="modal-content">
        <span :class="`close-${id}`" @click="closeSimplert" class="close" >&times;</span>
        <p>Er du sikker?</p>
        <div class="row">
          <div class="col-md-6">
            <button @click="deleteAction" type="button" class="btn btn-danger">Ja, slett</button>
          </div>
          <div class="col-md-6">
            <button @click="closeSimplert" type="button" :class="`close-${id}`" class="btn btn-info">Avbryt</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: ['id'],
  data () {
    return {
      modal: {},
      close: {},
    }
  },
  mounted() {
    this.modal = document.getElementById(this.id);
  },
  methods: {
    openSimplert () {
      this.modal.style.display = "block";
    },
    closeSimplert (event) {
      let closeTarget = event.target.classList.contains(`close-${this.id}`);
      if (closeTarget) {
        this.modal.style.display = "none";
      }
    },
    deleteAction() {
      let url = `extras/${this.id}`;
      let self = this;
      axios.delete(url)
        .then(() => self.$eventHub.$emit('extras.delete', this.id))
        .catch(function (error) {
          if (error.response) {
            console.log(error.response.data);
            console.log(error.response.status);
          }
        });
      this.modal.style.display = "none";
    }
  }
}
</script>

I use eventhub for emitting the events between alert and extras component. The problem I have is that when I delete an item, item is removed from the list immediately on the list that I render, but if I go to another page, and come back again to the page with extras component, the list has the item that was deleted, only on refresh you can see that it was removed. Is there a way I can somehow persist the new items array on delete without using Vuex for state management?

10th January, 2018

Leff7 started a new conversation Vue.js 2 - Removing Items From Array With Event Hub • 8 months ago

I am using Vue.js 2 with Laravel and I have a method inside one component where I send a delete request to the server, and emit the event inside the vue app. This is the method:

deleteAction() {
  let url = `extras/delete/${this.id}`;
  axios.delete(url);
  this.$eventHub.$emit('extras.delete', this.id);
  this.modal.style.display = "none";
}

And in the other component I am listening to the event and removing the item from the array of items that I use to render those items in the template:

<template>
  <div>
    <div v-for="item in items" class="media row">
      <div class="media-left col-sm-3">
        <a href="#">
          <img class="media-object" :src="item.image_path" :alt="item.title">
        </a>
      </div>
      <div class="media-body col-sm-6">
        <h4 class="media-heading">{{ item.title }}</h4>
        <p>{{ item.description }}</p>
      </div>
      <div class="col-sm-3 action-buttons">
        <a class="btn btn-info" href="/extras/create" role="button">Rediger</a>
        <alert :id="item.id"></alert>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: ['items'],
  data () {
    return {}
  },
  created() {
      this.$eventHub.$on('extras.delete',(id) => {
          this.items = this.items.filter(function(el) {
            return el.id !== id;
          });
      })
  }
}
</script>

But, even though I see the event happening in the debug tools under the events, the first item is only removed after the second attempt, and the all other items after the first one are removed normally with the first attempt. Why is this happening?

Leff7 started a new conversation Vue 2 Sweet Alert Opening Modals For Each Element Separately • 8 months ago

I am using vue.js 2 [SweetAlert plugin][1] in my project. I have created a simple Alert component where I use it:

<template>
  <div>
    <a @click="openSimplert" class="btn btn-info" role="button">Slett</a>
    <simplert>
    </simplert>
  </div>
</template>
<script>
export default {
  props: ['id'],
  data () {
    return {
      obj: {
        title: 'Alert Title',
        message: 'Alert Message',
        type: 'info',
        useConfirmBtn: true,
        customConfirmBtnText: 'OK'
      }
    }
  },
  methods: {
    openSimplert () {
      this.$Simplert.open(this.obj)
    },
    closeSimplert () {
      this.$Simplert.close()
    },
  }
}
</script>

The problem I have is that I am using this component in foreach loop in my laravel template:

               @foreach($data as $extra)
                  <div class="media row">
                    <div class="media-left col-sm-3">
                      <a href="#">
                        <img class="media-object" src="{{ $extra->image_path }}" alt="{{ $extra->title }}">
                      </a>
                    </div>
                    <div class="media-body col-sm-6">
                      <h4 class="media-heading">{{ $extra->title }}</h4>
                      <p>{{ $extra->description }}</p>
                    </div>
                    <div class="col-sm-3 action-buttons">
                      <a class="btn btn-info" href="/extras/create" role="button">Rediger</a>
                      <alert :id="{{ $extra->id }}"></alert>
                    </div>
                  </div>
                @endforeach

How can I now open only the modal for that one element where I click the alert button? Because now when I click it if I have 2 elements inside the foreach loop, I open 2 modals. [1]: https://github.com/mazipan/vue2-simplert-plugin

9th January, 2018

Leff7 started a new conversation Laravel 5.5 - Migration Not Working • 8 months ago

I am trying to run a migration that works perfectly fine on Laravel 5.2 version, but when I try to run it on the laravel 5.5 I get an error:

In Connection.php line 664:

SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'to_date' (SQL: create table transactions (id int unsigned not null auto_increment primary key, user_id int unsigned not null, vehicle_id int unsigned not null, from_date t imestamp not null, to_date timestamp not null, flight_number varchar(255) not null, created_at timestamp null, updated_at ti mestamp null) default character set utf8mb4 collate utf8mb4_unicode_ci)

In Connection.php line 458: SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'to_date'

This it the migration for that table:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTransactionsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('transactions', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')->references('id')->on('users');
            $table->integer('vehicle_id')->unsigned();
            $table->foreign('vehicle_id')->references('id')->on('vehicles');
            $table->timestamp('from_date');
            $table->timestamp('to_date');
            $table->string('flight_number');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('transactions');
    }
}

Why is it not working with the new version of laravel when it is working with the 5.2?

Leff7 left a reply on Laravel 5.2 Vue Integration • 8 months ago

This is the alert component:

<script>
import Simplert from 'vue2-simplert'

export default {
  data () {
    return {
      obj: {
        title: 'Alert Title',
        message: 'Alert Message',
        type: 'info',
        useConfirmBtn: true,
        customConfirmBtnText: 'OK'
      },
    }
  },
  methods: {
    openSimplert () {
      this.$refs.simplert.openSimplert(this.obj)
    },
  }
}
</script>

And this is the ImageInput component:

<template>
    <div>
        <div class="row">
            <div class="col-md-4">
                <div class="Image-input__image-wrapper">
                    <i v-show="! imageSrc" class="icon fa fa-picture-o"></i>
                    <img v-show="imageSrc" class="Image-input__image" :src="imageSrc">
                    <i v-show="imageSrc" @click="removeImage" class="remove fa fa-times"></i>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-4">
                <div class="Image-input__input-wrapper">
                    Last opp bilder
                    <input @change="previewThumbnail" class="Image-input__input" name="image" type="file">
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
  props: ['imageSrc'],
  methods: {
    previewThumbnail: function(event) {
      var input = event.target;

      if (input.files && input.files[0]) {
        var reader = new FileReader();

        var vm = this;

        reader.onload = function(e) {
          vm.imageSrc = e.target.result;
        }

        reader.readAsDataURL(input.files[0]);
      }
    },
    removeImage: function removeImage(e) {
      this.imageSrc = '';
      document.querySelectorAll('input[type=file]').forEach(element => {
          element.value = "";
      });
      document.getElementById('oldImage').value = '';
    }
  }
}
</script>

It is failing on both of this components.

Leff7 started a new conversation Laravel 5.2 Vue Integration • 8 months ago

I am trying to configure and integrate vue.js 2 with laravel 5.2. I have set up the package.json like this:

{
  "private": true,
  "scripts": {
    "prod": "gulp --production",
    "dev": "gulp watch"
  },
  "devDependencies": {
    "bootstrap-sass": "^3.0.0",
    "css-loader": "^0.28.8",
    "gulp": "^3.9.1",
    "laravel-elixir": "^6.0.0-9",
    "laravel-elixir-vue": "^0.1.4",
    "laravel-elixir-webpack-official": "^1.0.2",
    "vue": "^2.5.13",
    "vue-template-compiler": "^2.5.13"
  },
  "dependencies": {
    "vue2-simplert": "^0.7.1"
  }
}

And gulpfile looks like this:

var elixir = require('laravel-elixir');

require('laravel-elixir-vue-2');
/*
 |--------------------------------------------------------------------------
 | Elixir Asset Management
 |--------------------------------------------------------------------------
 |
 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
 | for your Laravel application. By default, we are compiling the Sass
 | file for our application, as well as publishing vendor resources.
 |
 */

elixir(function(mix) {
    mix.sass('app.scss')
       .webpack('app.js');
});

The app.js looks like this:

window._ = require('lodash');

window.Vue = require('vue');
Vue.component('image-input', require('./components/ImageInput.vue'));
Vue.component('alert', require('./components/ImageInput.vue'));

const app = new Vue({
    el: '#app'
});

But, then I get an error for each component:

[Vue warn]: Failed to mount component: template or render function not defined.

How can I set this up properly?

Leff7 started a new conversation Vue Sweet Alert Not Creating Element • 8 months ago

I would like to use this library for alerts in my app. I have installed it and created a component like this:

<script>
import Simplert from 'vue2-simplert'

export default {
  data () {
    return {
      obj: {
        title: 'Alert Title',
        message: 'Alert Message',
        type: 'info',
        useConfirmBtn: true,
        customConfirmBtnText: 'OK'
      },
    }
  },
  methods: {
    openSimplert () {
      this.$refs.simplert.openSimplert(this.obj)
    },
  }
}
</script>

I am registering the component in my app.js like this:

window.Vue = require('vue/dist/vue.common');
Vue.component('alert', require('./components/Alert.vue'));

const app = new Vue({
    el: '#app'
});

And then trying to use it in my template:

<alert :useRadius="true"
       :useIcon="true"
       ref="simplert">
</alert>

I can see the component in the vue debug tools, but no html is being created, I can only see this:

<!--function (a, b, c, d) { return createElement(vm, a, b, c, d, true); }-->

What is wrong, how can I fix this?

8th January, 2018

Leff7 started a new conversation Laravel 5.2 - Vue Integration • 8 months ago

I have a legacy project built with Laravel 5.2 version, and I am wondering how do setup Vue with it. I have added vue to the package.json file:

{
  "private": true,
  "scripts": {
    "prod": "gulp --production",
    "dev": "gulp watch"
  },
  "devDependencies": {
    "gulp": "^3.9.1",
    "laravel-elixir": "^5.0.0",
    "bootstrap-sass": "^3.0.0",
    "vue": "^2.0.1"
  }
}

I have created bootstrap.js and app.js files in resources/assets/js folder:

bootstrap.js

window._ = require('lodash');

/**
 * Vue is a modern JavaScript library for building interactive web interfaces
 * using reactive data binding and reusable components. Vue's API is clean
 * and simple, leaving you to focus on building your next great project.
 */

window.Vue = require('vue');

app.js

require('./bootstrap');

/**
 * First we will load all of this project's JavaScript dependencies which
 * include Vue and Vue Resource. This gives a great starting point for
 * building robust, powerful web applications using Vue and Laravel.
 */

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the body of the page. From here, you may begin adding components to
 * the application, or feel free to tweak this setup for your needs.
 */

Vue.component('image-input', require('./components/ImageInput.vue'));

const app = new Vue({
    el: '#app'
});

And this is the component ImageInput.vue:

<template>
    <div>
        <div class="row">
            <div class="large-6 columns">
                <div class="Image-input__image-wrapper">
                    <i v-show="! imageSrc" class="icon fa fa-picture-o"></i>
                    <img v-show="imageSrc" class="Image-input__image" :src="imageSrc">
                    <i v-show="imageSrc" @click="removeImage" class="remove fa fa-times"></i>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="large-6 columns">
                <div class="Image-input__input-wrapper">
                    Last opp bilder
                    <input @change="previewThumbnail" class="Image-input__input" name="image" type="file">
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {

  props: ['imageSrc'],

  methods: {
    previewThumbnail: function(event) {
      var input = event.target;

      if (input.files && input.files[0]) {
        var reader = new FileReader();

        var vm = this;

        reader.onload = function(e) {
          vm.imageSrc = e.target.result;
        }

        reader.readAsDataURL(input.files[0]);
      }
    },
    removeImage: function removeImage(e) {
      this.imageSrc = '';
      document.querySelectorAll('input[type=file]').forEach(element => {
          element.value = "";
      });
      document.getElementById('oldImage').value = '';
    }
  }
}
</script>

I have setup the gulpfile like this:

elixir(function(mix) {
    mix.sass('app.scss')
       .scripts('app.js');
});

But, after running gulp command in the terminal I get an error require is not defined and I then I don't see the component that ImageInput that I am using in one form. What am I doing wrong here?

14th December, 2017

Leff7 left a reply on WP - Not Saving All Of The Fields When Saving Data To Ninja Forms Plugin • 9 months ago

I am not saving to Laravel DB, I am sending data to remote WP DB.

Leff7 started a new conversation WP - Not Saving All Of The Fields When Saving Data To Ninja Forms Plugin • 9 months ago

I am sending data to Ninja forms plugin to save in the WP, based on the example of how to send data from the frontend, that I could see on the Ninja form docs. I have implemented that on my backend side built with laravel/php:

    $url = $this->postUrl . '/wp-admin/admin-ajax.php';
    $client = new Client();
    $response = $client->request('POST', $url, [
        'form_params' => [
            'security' => $this->getNonce(),
            'action' => 'nf_ajax_submit',
            'formData' => $request->formData,
        ]
    ]);

The formData looks like this:

{
  "id":"1",
  "fields":[
       {"id":"1","value":"My Name"},
       {"id": "2","value":"[email protected]"},
       {"id":"3","value":"some message"}
   ]
}

Where id is an id of that ninja form in WP in my case Contact form, and each object in the fields array represents a field in the form. Id of that object is an id of that field.In my case id 1 is an id of name field, and id 2 is an id of email field, while id 3 is an id of message field. The data is being saved normally to message and email field as you can see on the image below, but not to the name field.

enter image description here

On checking the WP DB postmeta table I could see that fields are being saved as:

post_id  |  meta_key   |   meta_value

  341           field_2        [email protected]
  341           field_3        some message
  341           field_   

So, the problem is that the name field is being saved as only field_ with no value, why is there a problem when the other fields are being saved as they should?

13th December, 2017

Leff7 started a new conversation WP - Not Saving All Of The Fields When Saving Data To Ninja Forms WP Plugin • 9 months ago

I am sending data to Ninja forms plugin to save in the WP. I am doing a post request where I am sending data for a contact form. The data looks like this:

{
  "id":"1",
  "fields":[
       {"id":"1","value":"My Name"},
       {"id": "2","value":"[email protected]"},
       {"id":"3","value":"some message"}
   ]
}

The problem I have is that both email and message are saved but the name is not:

enter image description here

Why is that, what am I doing wrong here?

Leff7 started a new conversation Php - Json_decode Returns Null • 9 months ago

I am trying to decode json string that looks like the one below with json_decode php function:

"{id:"1",fields:[{id:"1",value:"asdasd"},{id: "2",value:"asdasd"},{id:"3",value:"asdasd"}]}"

I have tried various options from this question. Like:

$foo = utf8_encode($json_string);
$data = json_decode($foo, true);

Or:

json_decode(str_replace ('\"','"', $json_string), true);

Even with:

json_decode( preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $json_string), true );

But, everything I try I always get null. Why is that?

12th December, 2017

Leff7 left a reply on Sending A Form-data Post Request With Guzzle Http • 9 months ago

But, I have tried doing that like so:

$response = $http->post('https://your-endpoint.com', [
    'form_params' => [
        'data' =>  $formData,
    ],
]);

And it didn't work, but when I have made request in the postman, where I have checked the form-data and sent the key value pairs for form fields in the body , then I got a message that form was submitted sucessfully.

Leff7 started a new conversation Sending A Form-data Post Request With Gizzle Http • 9 months ago

I am using gizzle http, and would like to implement the post request that looks like this when done with js:

                      var formData = JSON.stringify( { id: formID, fields: fields, settings: settings, extra: extra } );
            var data = {
                'action': 'nf_ajax_submit',
                'security': nfFrontEnd.ajaxNonce,
                'formData': formData
            }

            var that = this;

            jQuery.ajax({
                url: nfFrontEnd.adminAjax,
                type: 'POST',
                data: data,
                cache: false,
                success: function( data, textStatus, jqXHR ) {
                    try {
                        var response = jQuery.parseJSON( data );
                        nfRadio.channel( 'forms' ).trigger( 'submit:response', response, textStatus, jqXHR, formModel.get( 'id' ) );
                        nfRadio.channel( 'form-' + formModel.get( 'id' ) ).trigger( 'submit:response', response, textStatus, jqXHR );
                        jQuery( document ).trigger( 'nfFormSubmitResponse', { response: response, id: formModel.get( 'id' ) } );
                    } catch( e ) {
                        console.log( e );
                        console.log( 'Parse Error' );
                        console.log( e );
                    }

                },

How can I make a post request form-data with gizzle, I have tried with doing the same thing like this:

        $url = 'http://ytf.app/wp-admin/admin-ajax.php';
        $data = [];
        $data['security'] = $this->getNonce();
        $data['action'] = 'nf_ajax_submit';
        $data['formData'] = $request->all();
        $formData = json_encode($data);

        $client   = new Client();
        $response = $client->request('POST', $url, [
            'body' =>  $formData,
        ]);

        $body = json_decode($response->getBody(), true);

        if ($body['success'] === true && $body['data'] !== false) {
            return $body['data'];
        }

But, that is not working, how should I do this?

Leff7 started a new conversation Saving Data To Ninja Forms Through An Api • 9 months ago

I have a frontend built separately from the WP backend and I am fetching everything through an api that gets all the data from the WP backend. In this particular case I am getting fields data of the Ninja form plugin through an api and building the form with it on the frontend. This is how the endpoint looks like in the WP:

add_action('init', function() {

  function getNinjaFormData(WP_REST_Request $request) {
    $id = $request->get_param('id');
    $settings = ['label', 'type', 'required'];
    $formTitle = Ninja_Forms()->form( 1 )->get()->get_setting('title');
    $formFields = Ninja_Forms()->form(1)->get_fields();
    $data = ['title' => $formTitle];

    foreach ($formFields as $formField) {
      $key = $formField->get_setting('key');

      foreach ($settings as $setting) {
        $object[$setting]  = $formField->get_setting($setting);
      }
      $data['fields'][] = $object;
    }

    return $data;
  }
});

add_action('rest_api_init', function () {
  register_rest_route( 'ninja-forms/', '/id/(?P<id>\d+)', [
    'methods' => 'GET',
    'callback' => 'getNinjaFormData',
  ]);
});

So, I am sending data to the frontend that looks like this:

{
  "title": "Contact Me",
  "fields": [
    {
        "label": "Name",
        "type": "textbox",
        "required": "1"
    },
    {
        "label": "Email",
        "type": "email",
        "required": "1"
    },
    {
        "label": "Message",
        "type": "textarea",
        "required": "1"
    },
    {
        "label": "Submit",
        "type": "submit",
        "required": null
    }
  ]
}

And with that data I am building a form. How can I then make an endpoint where I would save submission data that I am sending from the frontend, like for example when I am sending data from the frontend for that form that looks like this:

Array
(
    [name] => asdasd
    [email] => [email protected]
    [message] => sadas
)

Since, I saw in the documentation that posting to the backend from the frontend looks like this:

        var formData = JSON.stringify( { id: formID, fields: fields, settings: settings, extra: extra } );
        var data = {
            'action': 'nf_ajax_submit',
            'security': nfFrontEnd.ajaxNonce,
            'formData': formData
        }

        var that = this;

        jQuery.ajax({
            url: nfFrontEnd.adminAjax,
            type: 'POST',
            data: data,
            cache: false,
            success: function( data, textStatus, jqXHR ) {
                try {
                    var response = jQuery.parseJSON( data );
                    nfRadio.channel( 'forms' ).trigger( 'submit:response', response, textStatus, jqXHR, formModel.get( 'id' ) );
                    nfRadio.channel( 'form-' + formModel.get( 'id' ) ).trigger( 'submit:response', response, textStatus, jqXHR );
                    jQuery( document ).trigger( 'nfFormSubmitResponse', { response: response, id: formModel.get( 'id' ) } );
                } catch( e ) {
                    console.log( e );
                    console.log( 'Parse Error' );
                    console.log( e );
                }

            },

I have tried implementing that in my Laravel controller:

    $url = 'http://my-app.app/wp-admin/admin-ajax.php';
    $data = [];
    $data['action'] = 'nf_ajax_submit';
    $data['formData'] = $request->all();
    $formData = json_encode($data);

    $client   = new Client();
    $response = $client->request('POST', $url, [
        'form_params' => [
            'data'   => $formData,
        ]
    ]);

    $body     = json_decode($response->getBody(), true);

    if ($body['success'] === true && $body['data'] !== false) {
        return $body['data'];
    }

    return null;

But it doesn't work, I get null for $body['success'].

Leff7 started a new conversation Vue Class Binding On This Input Field • 9 months ago

I would like to bind a class on the input field where this class is suppose to be applied. In my case I have input fields that I am dynamically creating and since I can't bind values with v-model for input fields that are dynamically created I can't bind the class with v-model data. This are the fields that I am creating inside of v-for loop:

     <input
        class="input is-large"
        :ref="input.label.toLowerCase()"
        :type="input.type"
        :name="input.label.toLowerCase()"
        :required="input.required == 1">
      <label>{{ input.label }}</label>

I would like to know how can I bind a class now with that input field, so that I can check if the input field has some kind of value, so for example something like this:

:class="hasValue: this.input.value != ''"

Hoe can I do that with Vue?

11th December, 2017

Leff7 started a new conversation Vue - Submitting Dynamically Created Form • 9 months ago

I am creating a form dynamically with the data that I get from the backend:

{
    "title": "Contact Me",
    "fields": [
        {
            "label": "Name",
            "type": "textbox",
            "required": "1"
        },
        {
            "label": "Email",
            "type": "email",
            "required": "1"
        },
        {
            "label": "Message",
            "type": "textarea",
            "required": "1"
        },
        {
            "label": "Submit",
            "type": "submit",
            "required": null
        }
    ]
}

In Vue the component where I am making this form looks like this:

<form @submit.prevent="submit()" class="form">
  <template v-for="input in ninjaForm.fields">
    <div v-if="input.type != 'submit' && input.type != 'textarea'" class="control">
      <input v-bind:value="form[input.label]" class="input is-large" :type="input.type" :required="input.required == 1">
      <label>{{ input.label }}</label>
    </div>
    <div v-if="input.type == 'textarea'" class="control">
      <textarea v-bind:value="form[input.label]" class="textarea"></textarea>
      <label>{{ input.label }}</label>
    </div>
    <div v-if="input.type == 'submit'">
      <button class="button is-primary">{{ input.label }}</button>
    </div>
  </template>
</form>

I would like to submit this data back to the backend, but I am not sure how to do that, when I am doing console.log(this.form) I get an observer object, and if I do console.log(payload) I get an empty params property. What am I doing wrong and how should I fix this so that I can send form data as a params object?

Leff7 left a reply on Php - Creating Json Object • 9 months ago

This gave me the wanted result:

foreach ($formFields as $formField) {
  $key = $formField->get_setting('key');

  foreach ($settings as $setting) {
    $object[$setting]  = $formField->get_setting($setting);
  }
  $data['fields'][] = $object;
}

return $data;

Leff7 left a reply on Php - Creating Json Object • 9 months ago

Then, I a result like this:

"fields": [
        {
            "name": [
                {
                    "label": "Name"
                }
            ]
        },
        {
            "name": [
                {
                    "type": "textbox"
                }
            ]
        },
        {
            "name": [
                {
                    "required": "1"
                }
            ]
        },
        {
            "email": [
                {
                    "label": "Email"
                }
            ]
        },

Leff7 started a new conversation Php - Creating Json Object • 9 months ago

I am trying to create a json object from the data that I get from Ninja Forms that would look like this:

  {
    "title": "Contact Me",
    "fields": [{ "label": "Name",
                 "type": "textbox",
                 "required": "1" },
               { "label": "Email",
                 "type": "email",
                 "required": "1"
               }]
   }

I am trying to do so, like this:

$settings = ['label', 'type', 'required'];
$formTitle = Ninja_Forms()->form( 1 )->get()->get_setting('title');
$formFields = Ninja_Forms()->form(1)->get_fields();
$data = ['title' => $formTitle];

foreach ($formFields as $formField) {
  $key = $formField->get_setting('key');

  foreach ($settings as $setting) {
    $data['fields'][$key][][$setting] = $formField->get_setting($setting);
  }
}

return $data;

But, the result of that looks like this:

{
    "title": "Contact Me",
    "fields": {
        "name": [
            { "label": "Name" },
            { "type": "textbox" },
            { "required": "1"}
        ],
        "email": [
            { "label": "Email" },
            { "type": "email" },
            { "required": "1" }
        ],

How can I do this, so that the result looks like the one I have shown above?

6th December, 2017

Leff7 started a new conversation Not Able To Open App With Npm Run • 9 months ago

I have a vue app, that is set up to run with command npm run dev on port 8080. I haven't run in it in a while, and today when I have tried to run it again I got an error:

Cannot GET /

This is the setup:

dev: {
    env: require('./dev.env'),
    port: 8080,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {},
    cssSourceMap: false
  }

I have changed the port because I thought that might be the issue, but even after changing the port to 8081 I still got the same error. What else can I do, I have tried running various version of:

  sudo lost -n -I:8080, 
  sudo lsof -n -iTCP:8080 | grep LISTEN,  
  sudo lsof -n -i4TCP:8080 | grep LISTEN 

to see what is running on that port, but I didn't get any output after this commands.

27th November, 2017

Leff7 started a new conversation Npm Rebuild Node-sass Fails • 9 months ago

I have an old project that has a grunt as build tool. I have installed the project dependencies and grunt cli. This is the package.json file:

{
  "name": "",
  "version": "0.0.1",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-sass": "^1.0.0",
    "node-sass": "^3.3.3"
  }
}

On trying to run grunt I got an error that I need to run npm rebuild node-sass, but I got a new error then:

npm ERR! Failed at the [email protected] postinstall script 'node scripts/build.js'. npm ERR! Make sure you have the latest version of node.js and npm installed. npm ERR! If you do, this is most likely a problem with the node-sass package, npm ERR! not with npm itself.

I have even tried with running the command with the --force flag. But that didn't work either, how can I fix this?

Leff7 started a new conversation How To Have Connect 2 Homestead Boxes With DB On One Virtual Machine • 9 months ago

I have 2 homestead boxes on one vagrant virtual machine. I only have one Homestead.yaml file for both boxes:

ip: "192.168.10.10"
memory: 2048
cpus: 1
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: ~/Desktop/Projects
      to: /home/vagrant/Projects

sites:
    - map: middleton.app
      to: /home/vagrant/Projects/middleton/public
    - map: drupal-test.app
      to: /home/vagrant/Projects/drupal-test
    - map: presafe.app
      to: /home/vagrant/Projects/presafe
    - map: mariva-new.app
      to: /home/vagrant/Projects/laravel-new/public
    - map: ytf.app
      to:  /home/vagrant/Projects/ytf
    - map: ytf-middleton.app
      to:  /home/vagrant/Projects/ytf-middleton/public
    - map: advent.app
      to:  /home/vagrant/Projects/advent/public
    - map: velgriktig.app
      to:  /home/vagrant/Projects/velgriktig

databases:
    - middleton

# blackfire:
#     - id: foo
#       token: bar
#       client-id: foo
#       client-token: bar

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp

How can I make them so that they point to different DBs, each box to it's own?

Leff7 started a new conversation Reseting The Mysql Password On A Homestead Box • 9 months ago

I have 2 boxes on my virtual machine, one with php v.7 and the other with php v.5.6. I have installed the latter one, just recently and I have updated to macOS High Sierra. Today I realised that I can't access anymore sites that I have locally, I get the error:

Your password has expired. To log in you must change it using a client that supports expired passwords.

I went to reset the password on vagrant machine again by running this command, and then was prompted to reset password, which I have just set up to the old one that I already had:

mysqladmin -u root -p password
Enter password: 
New password: 
Confirm new password:

I have then run vagrant halt and vagrant up, but nothing has changed, I have still got the same error as previously.

24th November, 2017

Leff7 started a new conversation Vagrant\Homestead - Setting Up Multiple Php Versions • 9 months ago

I have installed virtual box on my machine few months ago, and I have read that it is possible to set the PHP version per project in Homestead.yaml file, here in the laravel docs. In the warning there it says

this feature is only compatible with Nginx

I thought we are running Nginx on Homestead? How can I also check if I am having the latest homestad version since this is possible only since Homestead 6 release. I have with homestead-v but that gave me an error that the homestead command was not found.

23rd November, 2017

Leff7 started a new conversation Php - Making A Class Instance That Has Dependencies In The Constructor • 9 months ago

I have a class, that has a constructor that looks like this:

use App\Libraries\Content\ContentInterface;
use EllipseSynergie\ApiResponse\Laravel\Response;

class ImportController extends Controller
{
    private $indexable;

    function __construct(Response $response, ContentInterface $contentInterface) {
        $this->indexable        = \Config::get('middleton.wp.content.indexable_types');
        $this->response         = $response;
        $this->contentInterface = $contentInterface;
    }

    public function all() {
        $include      = array_diff($this->indexable, ['folder']);
        $importResult = $this->import($include);
        $this->deleteOldContent($importResult['publishedPostsIDs']);

        return $importResult['imported'];
    }

How can I instantiate this class from another class and call the method all() from it? I have tried with something like this:

use EllipseSynergie\ApiResponse\Laravel\Response;
use App\Libraries\Content\ContentInterface;

class ContentImport extend Command {

public function handle() {

    (new ImportController(new Response, new ContentInterface))->all();
}

But, that doesn't work, I get the error that I should pass the arguments to the Response class too:

 [Symfony\Component\Debug\Exception\FatalThrowableError]                                                                    
  Type error: Too few arguments to function EllipseSynergie\ApiResponse\AbstractResponse::__construct(), 0 passed in /home/  
  vagrant/Projects/middleton/app/Console/Commands/ContentImport.php on line 43 and exactly 1 expected  

What is the correct way of doing this?

Leff7 started a new conversation Laravel Task Scheduling- Making Multiple Commands And Tasks • 9 months ago

I am trying to make 2 artisan commands that would each do a different task that should also be scheduled to do their tasks each day. So far, I have set it up like this:

I have created a FolderImport class in the Console/Commands directory:

class FolderImport extends Command
{
 
  protected $signature = 'import:folders';

  /**
  * The console command description.
  *
  * @var string
  */
  protected $description = 'Imports folders';

  /**
  * Create a new command instance.
  *
  * @return void
  */
  public function __construct(ImportController $folders)
  {
      parent::__construct();

      $this->folders = $folders;
  }

  /**
  * Execute the console command.
  *
  * @return mixed
  */
  public function handle()
  {
      $this->folders->scheduledImport();
  }

}

And the ContentImport class:

class ContentImport extends Command
{
  protected $signature = 'import:content';

  /**
  * The console command description.
  *
  * @var string
  */
  protected $description = 'Imports content';

  /**
  * Create a new command instance.
  *
  * @return void
  */
  public function __construct(ImportController $content)
  {
      parent::__construct();

      $this->content = $content;
  }

  /**
  * Execute the console command.
  *
  * @return mixed
  */
  public function handle()
  {
      $this->content->scheduledImport();
  }
}

And then in the Kernel file I have added them like this:

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        Commands\Inspire::class,
        Commands\ContentImport::class,
        Commands\FolderImport::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('import:content')
            ->withoutOverlapping();

        $schedule->command('import:folders')
            ->withoutOverlapping();

        $schedule->call('App\Http\Controllers\[email protected]')
            ->dailyAt('00:00');

        $schedule->call('App\Http\Controllers\[email protected]')
            ->dailyAt('00:00');
    }
}

How can I connect the import:folders command with the call to [email protected] and the command import:content to the call to [email protected]?

14th November, 2017

Leff7 left a reply on Laravel - Integrity Constraint Violation: 1452 Cannot Add Or Update A Child Row • 10 months ago

Yes, that was it, thank you!

13th November, 2017

Leff7 started a new conversation Laravel - Integrity Constraint Violation: 1452 Cannot Add Or Update A Child Row • 10 months ago

I am importing some content from remote WP database to local DB with laravel. I have set up the tables inventories and contents.

Inventories table looks like this:

    Schema::create('inventories', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('remote_id')->unsigned();
        $table->integer('local_id')->unsigned();
        $table->string('local_type');
        $table->timestamps();

        $table->foreign('local_id')->references('id')->on('contents')->onDelete('cascade');
    });

This is the contents table:

    Schema::create('contents', function (Blueprint $table) {
        $table->increments('id')->unsigned();
        $table->integer('ct_id')->unsigned();
        $table->foreign('ct_id')->references('id')->on('content_types');
        $table->integer('cms_id');
        $table->string('title');
        $table->string('slug');
        $table->text('excerpt');
        $table->mediumText('body');
        $table->string('password');
        $table->integer('parent_id');
        $table->timestamps();
    });

I have made functions to import all and import single posts from remote WP DB. This is the import for all posts:

public function all()
{
    $include      = array_diff($this->indexable, ['folder']);
    $publishedPostsIDs = $this->import($include);
    $this->deleteOldContent($publishedPostsIDs);
}

private function import($include)
{
    $posts             = Post::where('post_status', 'publish')->whereIn('post_type', $include)->get();
    foreach ($posts as $post) {
        $publishedPostsIDs[] = $post->ID;
        $this->contentInterface->updateOrCreateInventory($post->ID);
    }

    return $publishedPostsIDs;
}

public function updateOrCreateInventory($remoteId)
{
    $this->contentInterface->updateOrCreateInventory($remoteId);
}

private function deleteOldContent($publishedPostsIDs)
{
    $contentToDelete = Content::whereNotIn('cms_id', $publishedPostsIDs)->get();

    if (count($contentToDelete) > 0) {
        foreach ($contentToDelete as $content) {
            $content->delete();
        }
    }
}

So, when I am importing all, I just go to the route that goes to all function, and all the posts from remote WP DB that are not of post type folder are imported. If I want to import a single post from remote DB, then I have a route that goes directly to the updateOrCreateInventory function. I also have import for the posts of type folder, which is basically almost the same as the function all.

public function folder()
{
    $include = ['folder'];
    $importResult = $this->import($include);

    return $importResult['imported'];
}

The problem I have is that when I am importing all folders at once I get an error:

QueryException in Connection.php line 729: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (middleton.inventories, CONSTRAINT inventories_local_id_foreign FOREIGN KEY (local_id) REFERENCES contents (id) ON DELETE CASCADE) (SQL: insert into inventories (remote_id, updated_at, created_at) values (7512, 2017-11-13 15:33:17, 2017-11-13 15:33:17))

But, if I try to import that same folder individually , or to be more exact that same post of type folder, I don't get any error and the post is imported. How is that possible?

Edit Your Profile
Update

Want to change your profile photo? We pull from gravatar.com.